2019年6月23日
变量提升-函数提升(转)
变量提升
下面的代码中,我们在函数中声明了一个变量,不过这个变量声明是在if语句块中:
function hoistVariable() { if (!foo) { var foo = 5; } console.log(foo); // 5 } hoistVariable();
运行代码,我们会发现foo的值是5,
那么至于说打印结果,经过一次预编译之后,上面的代码逻辑如下:
// 预编译之后 function hoistVariable() { var foo; if (!foo) { foo = 5; } console.log(foo); // 5 } hoistVariable();
引擎将变量声明提升到了函数顶部,初始值为undefined,自然,if语句块就会被执行,foo变量赋值为5,下面的打印也就是预期的结果了。
类似的,还有下面一个例子:
var foo = 3; function hoistVariable() { var foo = foo || 5; console.log(foo); // 5 } hoistVariable();
foo || 5这个表达式的结果是5而不是3,虽然外层作用域有个foo变量,但函数内是不会去引用的,因为预编译之后的代码逻辑是这样的:
var foo = 3; // 预编译之后 function hoistVariable() { var foo; foo = foo || 5; console.log(foo); // 5 } hoistVariable();
如果当前作用域中声明了多个同名变量,那么根据我们的推断,它们的同一个标识符会被提升至作用域顶部,其他部分按顺序执行,比如下面的代码:
function hoistVariable() { var foo = 3; { var foo = 5; } console.log(foo); // 5 } hoistVariable();
由于JavaScript没有块作用域,只有全局作用域和函数作用域,所以预编译之后的代码逻辑为:
// 预编译之后 function hoistVariable() { var foo; foo = 3; { foo = 5; } console.log(foo); // 5 } hoistVariable();
函数提升
function hoistFunction() { foo(); // output: I am hoisted function foo() { console.log('I am hoisted'); } } hoistFunction();
为什么函数可以在声明之前就可以调用,并且跟变量声明不同的是,它还能得到正确的结果,其实引擎是把函数声明整个地提升到了当前作用域的顶部,预编译之后的代码逻辑如下:
// 预编译之后 function hoistFunction() { function foo() { console.log('I am hoisted'); } foo(); // output: I am hoisted } hoistFunction();
相似的,如果在同一个作用域中存在多个同名函数声明,后面出现的将会覆盖前面的函数声明
function hoistFunction() { function foo() { console.log(1); } foo(); // output: 2 function foo() { console.log(2); } } hoistFunction();