JavaScript 提升是指解释器在执行代码之前,似乎将函数、变量、类或导入的声明移动到其作用域的顶部的过程。
任何一下行为都可被视为提升:
- 能够在声明变量之前在其作用域中使用该变量的值。(值提升)
- 能够在声明变量之前在其作用域中引用该变量而不抛出
ReferenceError
,但值始终是undefined
。(“声明提升”) - 变量的声明导致在声明行之前的作用域中行为发生变化。
- 声明的副作用在评估包含该声明的其余代码之前产生。
函数声明提升
结论:函数声明提升属于第1种
foo(); // foo function foo() { console.log("foo") }
foo
函数在声明前可以被调用,也就是在声明前使用了该变量的值,所以属于值提升。
var
声明的变量提升属于
结论:var
声明的变量提升属于第2种
console.log(age); // undefined var age = 18;
输出结果为undefined
,也就是说明var
变量被提升,但没赋值;
let
、const
、class
的声明提升
结论:let
、const
、class
的声明提升属于第3种
console.log(age); // ReferenceError: Cannot access 'age' before initialization let age = 18;
console.log(name); // ReferenceError: Cannot access 'name' before initialization const name = "jack";
console.log(new Person()); // ReferenceError: Cannot access 'Person' before initialization class Person {}
let
、const
、class
声明的变量在声明前使用,都出现ReferenceError
错误,表示变量没有初始化,说明这些变量实际已经被定义了,只是没有初始化。
import
的声明提升
结论:import
的声明提升属于第1种和第4种
// a.js console.log("this is a.js"); export const foo = 18;
// b.js console.log("this is b.js"); console.log(foo); import {foo} from "./a.js";
运行b.js的结果如下:
this is a.js this is b.js 18
this is a.js
先输出,this is b.js
后输出,同时console.log(foo)
也正确的输出了值;
所以import
确实进行了提升,并且foo
变量是值提升,同时a.js
的的内容先输出;所以import
提升属于第1种和第4种。