JS代码运行之预编译

变量提升

  • var 定义的变量会提升到最顶部,所以可以使用这个变量前声明或者使用后声明
  • constlet 一定要先声明才能使用
  • 函数声明也会提升到最顶部
    function a() {} // 这个是函数声明
    var a = function () {} 这个是声明了一个变量a,给a赋值一个函数体,不是函数声明!!!

JS 代码运行的3大步骤

  • 词法分析:顾名思义就是检查一遍js代码内有没有出现语法错误(比如少写分好,多写括号等);词法分析阶段不执行代码。
  • 预编译:这个阶段发生在代码执行的前一刻,这个过程就是在内存里创建一个空间,用来存放你定义的变量和函数
  • 解释执行:执行代码

GO和 AO

  • JS 在执行前会产生一个GO(global object),也就是全局作用域
  • 当一个方法被调用时会形成一个局部作用域AO(activation object)

预编译的执行步骤

暗示全局变量(imply global)

  • 学习预编译前要知道的事情:任何变量如果未经声明就赋值,那么此变量就为全局对象所有。

GO对象

  • 创建GO对象
  • 寻找变量声明,值设定为undefined。
  • 寻找函数中的函数声明,将函数名作为GO属性名,值为函数体。

AO对象

  • 创建AO对象
  • 寻找函数的形参和变量声明,将变量和形参名作为AO对象的属性名,值设定为undefined。
  • 将形参和实参相统一,即更改形参后的undefined为具体的形参值。
  • 寻找函数中的函数声明,将函数名作为AO属性名,值为函数体。

至此,预编译环节结束,函数中变量按照AO对象中的值开始执行

举几个🌰

eg1

function fn(a) {
    console.log(a);
    var a = 123;
    console.log(a);
    function a() {};
    console.log(a);
    var b = function () {};
    console.log(b);
    function d() {};
}
fn(1);

以下都是伪代码,是我们肉眼看不见的

第一步: 词法分析有没有语法错误

第二步: 开始预编译

1、先创建一个全局对象GO

	GO{}

2、寻找变量声明,值设定为undefined,这个例子里面没有变量声明

	GO{}

3、寻找函数中的函数声明,将函数名作为GO属性名,值为函数体

	GO{
		fn:function // 我们用function来代替函数体
	}

4、GO寻找完了之后,开始寻找AO,先创建一个AO

	AO{}

5、寻找函数的形参和变量声明,将变量和形参名作为AO对象的属性名,值设定为undefined。用var声明的变量都是AO的属性名

	AO{
		a: undefined, // 形参
		b: undefined, // 用var声明的变量,虽然给它赋值的是函数,但是它还是变量,不属于函数声明
	}

6、将形参和实参相统一,即更改形参后的undefined为具体的形参值。

	AO{
		a: 1, // 形参和实参相统一,fn(1),这里的实参是1
		b: undefined, // 用var声明的变量,虽然给它赋值的是函数,但是它还是变量,不属于函数声明
	}

7、寻找函数中的函数声明,将函数名作为AO属性名,值为函数体。

	AO{
		a: function, // 发现了函数声明 function a() {};
		b: undefined, // 用var声明的变量,虽然给它赋值的是函数,但是它还是变量,不属于函数声明
		d:function,// 发现了函数声明 function d() {};
	}

这个时候其实相当于fn函数里面代码是这个样子的:

	function fn(a) {
		function a() {}; // 函数提升到上面
		function d() {}; // 函数提升到上面
	    console.log(a);
	    var a = 123;
	    console.log(a);
	    console.log(a);
	    var b = function () {}; // 这个是变量声明,不是函数声明
	    console.log(b);
	}

第三步: 代码解释执行

1、遇到第一个console.log(a); 这个时候看看AO里面的a的值是什么

	AO{
		a: function, // 发现了函数声明 function a() {};
		b: undefined, // 用var声明的变量,虽然给它赋值的是函数,但是它还是变量,不属于函数声明
		d:function,// 发现了函数声明 function d() {};
	}

可以执行输出function a() {}

2、下一行var a = 123,给a赋值了,所以AO里面进行修改

	AO{
		a: 123, // 给a赋值123
		b: undefined, // 用var声明的变量,虽然给它赋值的是函数,但是它还是变量,不属于函数声明
		d:function,// 发现了函数声明 function d() {};
	}

3、又遇到了console.log(a);

	AO{
		a: 123, // 给a赋值123
		b: undefined, // 用var声明的变量,虽然给它赋值的是函数,但是它还是变量,不属于函数声明
		d:function,// 发现了函数声明 function d() {};
	}

这个时候看AO里面a的值已经是123了,所以输出123

4、下一行有function a() {}; 这个函数声明已经在预编译阶段就提升了,所以看下一行。

5、再次遇到了console.log(a);

	AO{
		a: 123, // 给a赋值123
		b: undefined, // 用var声明的变量,虽然给它赋值的是函数,但是它还是变量,不属于函数声明
		d:function,// 发现了函数声明 function d() {};
	}

这个时候没有对a作任何改变,所以依然输出123

6、 var b = function () {}; 这行对b做了一个赋值,赋值给它一个函数体,所以我们对AO进行修改

	AO{
		a: 123, // 给a赋值123
		b: function, // 赋值函数体 function () {}
		d:function,// 发现了函数声明 function d() {};
	}

7、console.log(b); 这个时候看看AO里面的b的值是什么

	AO{
		a: 123, // 给a赋值123
		b: function, // 赋值函数体 function () {}
		d:function,// 发现了函数声明 function d() {};
	}

可以看到是function,所以输出function () {}

后面几个例子可以自己试试,套用上面的步骤来操作

eg2

function test(a,b){
    console.log(a);
    c = 0;
    var c;
    a = 3;
    b = 2;
    console.log(b);
    function b() {};
    function d() {};
    console.log(c);
}
test(1);

eg3

console.log(fun);
function fun(fun){
    console.log(fun);
    var fun = 234;
    console.log(fun);
    function fun () {};
}
fun(1);
var fun = 123

eg4

function demo(){
    console.log(bb);
    if (aa) {
        var bb = 100;
    }
    console.log(bb);
    cc = 234
    console.log(cc);
}

var aa;
demo();
aa = 10;
console.log(cc);

eg5

a = 100;

function eg(e){
    function a() {};
    arguments[0] = 2;

    console.log(e);
    if (a) {
        var b = 123;
        var c = function(){}
    }
    var c;
    a = 10;
    var a;
    console.log(b);
    f = 123;
    console.log(c);
    console.log(a);
}

var a;
eg(1);
console.log(a);
console.log(f);

公众号

欢迎大家关注我的公众号: 石马上coding,一起成长
石马上coding

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值