读书笔记《你不知道的JavaScript上卷》1.4提升

版权声明:本文为博主逝水流光原创,可以转载,请注明出处。 https://blog.csdn.net/javao_0/article/details/74977930

4.1 首先看现象

代码1:

a = 2;
var a;
console.log( a );//打印2

代码2:

console.log( a );//打印undefined
var a = 2;

上面这两个就是体现了JS中变量提升的简单示例,为什么是这样呢?

4.2 提升的本质

之前说过JS代码的执行会经过两个阶段,一个是编译阶段,一个是执行阶段。现有语句“var a = 2;“其实相当于“var a;”和“a = 2;”两条语句,其中第一个声明语句是在编译阶段进行的,第二个赋值语句是在执行阶段进行的,正因为这样所以声明语句的运行要先于赋值语句,所以就会有上面这种现象。

提升:由于声明所在的编译阶段要先于赋值所在的执行阶段,这个过程就好像变量和函数声明从它们在代码中出现的位置被“移动”到了最上面,这个过程就叫做提升。

这就好像4.1中的代码2可以看成如下代码(提升是由于上述2个阶段引起的,通常我们都会把变量的提升理解为代码写在作用域的第一行,这样有助于我们分析代码,并且结果跟正确的结果是一致的):

var a;//声明相当于出现在作用域的第一行

console.log( a );//执行的时候还没有执行到赋值语句所以打印undefined
a = 2;

这样一来一切就明朗了。

4.3 函数的提升

函数和变量一样也会提升,这里会牵扯到一个顺序的问题,看如下代码:

foo(); // 这里打印3
function foo() {//这个foo是函数的声明会被提升,相当于放在了作用域的起始位置
    console.log(1);
}
var foo = function() {//这个foo是变量(虽然赋值以后是函数),所以变量会被提升(但没有赋值),不过由于上面的foo已经提升了,也就是已经声明过了,这种情况这里的foo单纯的var声明将会被忽略。
    console.log(2);
};
function foo() {//这个foo也会被提升,并且会覆盖之前提升的foo,所以打印3
    console.log(3);
}

由上可知,对于同一个名称的提升,如果变量写在前面的话,那么函数的提升会覆盖变量的提升,如果函数写在前面的话,后面变量的提升(var声明这种情况)将会忽略,所以可以总结出函数的提升优先于变量的提升

4.4 变量提升的坑

现在考虑一种比较特殊的提升,代码如下:

foo(); // TypeError
bar(); // ReferenceError
var foo = function bar() {
    console.log(123);
};

上述代码中foo是TypeError应该不会有什么疑问的,由于foo是var声明的所以会提升,当执行的时候foo还没有赋值所以是undefined,所以直接以函数的形式调用是不行的,所以TypeError。对于bar这种情况,由于bar被赋值给foo,这种具名函数将会在函数外面被忽略,所以相对于函数外部来说bar相当于不写,故调用bar,会出现ReferenceError,这里说明一点,即使bar在最后一行调用也是不行的,因为bar在函数外部是忽略的。上述代码可以看做如下代码:

var foo;//foo提升了

foo(); // TypeError
bar(); // ReferenceError

foo = function() {
    var bar = foo;//只有在函数内部才能访问到bar
    console.log(123);
};

猜你喜欢

转载自blog.csdn.net/javao_0/article/details/74977930
今日推荐