多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
## 1.4 提升 考虑一下代码 ~~~ a = 2; var a; console.log( a ); //2 ~~~ ~~~ console.log( a ); //undefined var a = 2; ~~~ ### 1.4.1 回忆编译器 引擎会在解释JavaScript 代码之前首先对其进行编译。编译阶段中的一部分工作就是找到所有的声明,并用合适的作用域将它们关联起来。 因此:包括变量和函数在内的所有声明都会在任何代码被执行前首先被处理。 对第二段代码,JavaScript 实际上会将其看成两个声明:`var a; 和a = 2;`。第一个定义声明是在编译阶段进行的。第二个赋值声明会被留在原地等待执行阶段。 即: ~~~ var a; console.log( a ); a = 2; ~~~ **所有的声明(变量和函数)都会被“移动”到各自作用域的最顶端,这个过程被称为提升。** * 只有声明本身会被提升,而赋值或其他运行逻辑会留在原地。如果提升改变了代码执行的顺序,会造成非常严重的破坏。 * 每个作用域都会进行提升操作。 * 函数声明会被提升,但是函数表达式却不会被提升。 ~~~ foo(); // 不是ReferenceError, 而是TypeError! var foo = function bar() { // ... }; ~~~ * 即使是具名的函数表达式,名称标识符在赋值之前也无法在所在作用域中使用: ~~~ foo(); // TypeError bar(); // ReferenceError var foo = function bar() { // ... }; ~~~ 提升后,即 ~~~ var foo; foo(); //typeError bar(); //ReferenceError foo = function(){ var bar = ....self...; //... } ~~~ ### 1.4.2 函数提升 函数声明和变量声明都会被提升。但是一个值得注意的细节(这个细节可以出现在有多个“重复”声明的代码中)是函数会首先被提升,然后才是变量。 ~~~ foo(); // 1 var foo; function foo() { console.log( 1 ); } foo = function() { console.log( 2 ); }; ~~~ 尽管重复的var 声明会被忽略掉,但出现在后面的函数声明还是可以覆盖前面的。 ~~~ foo(); // 3 function foo() { console.log( 1 ); } var foo = function() { console.log( 2 ); }; function foo() { console.log( 3 ); } ~~~ 一个普通块内部的函数声明通常会被提升到所在作用域的顶部,这个过程不会像下面的代码暗示的那样可以被条件判断所控制:(尽可能避免在块内部声明函数) ~~~ foo(); // "b" var a = true; if (a) { function foo() { console.log("a"); } } else { function foo() { console.log("b"); } } ~~~