提升

关于提升,记住几个要点,后面所有的判断套这个要点就行:

1,执行代码时,第一步总是静态编译,编译器会解析所有声明的变量,然后绑定到相对应的作用域中,而第二步,引擎才会开始执行赋值等操作;

2,函数声明永远优先于变量声明,同样的函数声明,后者覆盖前者;

来看例子:

a = 2;
var a;
console.log(a);

第一步会进行分词解析,a=2,实际上会先对a进行词法分析,当前作用域下没有(注意此时还没运行到var a),因此自动在全局作用域下定义一个a变量。

第二步,是var a,因为当前作用域(全局下)已经定义了变量a,因此该步骤被忽略。(这里直接跳过了赋值,是因为赋值是引擎的执行动作,只有在静态编辑之后,代码执行前几微妙才开始执行。)

以上两步完成后,编译工作完成,接下来是引擎执行环节。

第一步,对a进行赋值操作,LHS查找,直接赋值为2.

第二步,对console进行RHS查找,然后确认console对象下有log方法,然后对a进行RHS查找,在当前作用域下找到了a为2,因此执行打印出2。

再看例子:

console.log(a);
var a = 2;

第一步,编译过程,只有var a是变量声明,因此定义变量a。

至此,编译完成,引擎上场

第一步,执行console.log(a),和上面一样,两次RHS,发现a未定义,因为a的赋值在它后面,所以打印undefined

foo();
function(){}

为什么函数声明可以提升,因为函数声明它没有执行赋值操作,它是编译的过程就完成了,因此执行函数的时候,已经有了定义。

foo();
var foo = function(){}

这个就会报错了,报什么错?TypeError,因为var foo会在编译阶段优先执行,而foo()会进行RHS查找,找到了foo,但是foo不是一个函数,不能执行,因此报类型错误。

foo();

var foo;

function foo(){console.log(1)}

foo = function() {console.log(2)}

上面代码执行顺序应该是:

function foo() {console.log(1)}

var foo;

foo();

foo = function(){console.log(2)}

这里foo不会被覆盖掉,因为会被忽略掉,原因参见编译第一步分词/词法分析。

结合编译原理再来看这些代码真的非常容易理解,并且没有任何的问题。

end

猜你喜欢

转载自www.cnblogs.com/yanchenyu/p/9001121.html