本文共 5290 字,大约阅读时间需要 17 分钟。
JavaScript是一种动态语言,不同于C、Java等静态语言先编译后执行,
所以代码中的执行顺序并不像你看到的那样执行,有个词你需要知道声明提升,
下面我们就来聊聊声明提升。
1 2 3 | a = 1; var a; console.log(a); // 1 |
结果是1
,不是undefined
。虽然在var a;
在a = 1;
后面,但是存在声明提升,等价于:
1 2 3 | var a; a = 1; console.log(a); |
1 2 | console.log(a); // undefined var a = 1; |
为什么这次结果就是undefined
了,声明同样提升了,但是。。。等下再告诉你,上面的代码等价于:
1 2 3 | var a; console.log(a); // undefined a = 2; |
也就是说声明虽然提升了,但是赋值操作(执行)被留在了本身的位置。
引擎在对解释js的代码的时候,首先进行的是编译。
找到所有的声明,并用合适的作用域把它们关联起来。 so,var a = 2
,js会将其看成两个声明var a; a = 2;
1 2 3 4 5 6 | foo(); function foo() { console.log(a); // undefined var a = 2; } |
这个就很好理解了吧,那么你回答下一个
1 2 3 4 5 6 | foo(); var foo = function bar() { console.log(a); var a = 2; } |
先别说你的答案,估计你也猜错了,不是undefined
也不是2
;
因为还没执行到bar()
,foo()
就已经报错了TypeError
,函数声明可以提升,但是函数表达式的声明不能提升。
即使是具名函数表达式,在名称标识符在赋值之前也无法在作用域中使用:
1 2 3 4 5 6 7 | foo(); // TypeError; bar(); // ReferenceError; var foo = function bar() { console.log(a); var a = 2; } |
其实经过提升之后,代码变成了:
1 2 3 4 5 6 7 8 9 10 11 | var foo; foo(); // TypeError; bar(); // ReferenceError; foo = function () { var bar = function () { console.log(a); var a = 2; } } |
1 2 3 4 5 6 7 8 9 10 11 | foo(); // 1 var foo; function foo () { console.log(1); } foo = function () { console.log(2); } |
输出的是1,而不是2。
1 2 | var foo; function foo () {...} |
这两个都是声明,但是在声明中函数会首先被提升(var foo
同时被忽略了)。也就变成了:
1 2 3 4 5 6 7 8 | function foo() { console.log(1); } foo(); // 1 foo = function () { console.log(2); } |
注: 重复声明,后面函数声明会覆盖前面的。
1 2 3 4 5 6 7 8 9 10 11 12 13 | foo(); // 3 function foo() { console.log(1); } foo = function () { console.log(2); } function foo() { console.log(3); } |
为了避免踩坑,我们要做到先声明,避免重复声明。
转载地址:http://mxrni.baihongyu.com/