定义
JavaScript中奇怪的一点是你可以在变量和函数声明之前使用它们。就好像是变量声明和函数声明被提升了代码的顶部一样。
sayHi() // Hi there!
function sayHi() {
console.log('Hi there!')
}
name = 'John Doe'
console.log(name) // John Doe
var name
解析
在编译阶段阶段,代码真正执行前的几毫秒,会检测到所有的变量和函数声明,所有这些函数和变量声明都被添加到名为Lexical Environment的JavaScript数据结构内的内存中。所以这些变量和函数能在它们真正被声明之前使用。
函数提升
sayHi() // Hi there!
function sayHi() {
console.log('Hi there!')
}
环境查看
lexicalEnvironment = {
sayHi: < func >
}
var变量提升
console.log(name) // 'undefined'
var name = 'John Doe'
console.log(name) // John Doe
上面的代码可以分为两个部分
- var name表示声明变量name
- = 'John Doe'表示的是为变量name赋值为'John Doe'。
只有声明操作var name会被提升,而赋值这个操作并不会被提升,当JavaScript在编译阶段会找到var关键字声明的变量会添加到词法环境中,并初始化一个值undefined,在之后执行代码到赋值语句时,会把值赋值到这个变量。
// 编译阶段
lexicalEnvironment = {
name: undefined
}
// 执行阶段
lexicalEnvironment = {
name: 'John Doe'
}
所以函数表达式也不会被“提升”。helloWorld是一个默认值是undefined的变量,而不是一个function。
helloWorld(); // TypeError: helloWorld is not a function
var helloWorld = function(){
console.log('Hello World!');
}
let & const提升
console.log(a) // ReferenceError: a is not defined
let a = 3
事实上所有的声明(function, var, let, const, class)都会被“提升”。但是只有使用var关键字声明的变量才会被初始化undefined值,而let和const声明的变量则不会被初始化值。 只有在执行阶段JavaScript引擎在遇到他们的词法绑定(赋值)时,他们才会被初始化。这意味着在JavaScript引擎在声明变量之前,无法访问该变量。这就是我们所说的Temporal Dead Zone,即变量创建和初始化之间的时间跨度,它们无法访问。 如果JavaScript引擎在let和const变量被声明的地方还找不到值的话,就会被赋值为undefined或者返回一个错误(const的情况下)。
let a
console.log(a) // undefined
a = 5
如果我们要在变量声明之前使用变量,JavaScript引擎会从词法环境中获取变量的值,但是变量此时还是uninitialized状态,所以会返回一个错误ReferenceError。 在执行阶段,当JavaScript引擎执行到变量被声明的时候,如果声明了变量并赋值,会更新词法环境中的值,如果只是声明了变量没有被赋值,那么JavaScript引擎会给变量赋值为undefined。
此处理解为变量提升并非是一种物理意义上的提升,而是看起来像是声明被提升在代码执行之前。所以let变量声明后,可以被引擎赋值为undefined,但若是没有声明,则会去环境中查找。所以要想运用let,就必须保证在代码执行之前进行let声明。
tips: 我们可以在let和const声明之前使用他们,只要代码不是在变量声明之前执行:
function foo() {
console.log(name)
}
let name = 'John Doe'
foo() // 'John Doe'
class提升
同let和const一样,class在JavaScript中也是会被“提升”的,在被真正赋值之前都不会被初始化值, 同样受Temporal Dead Zone的影响。
let peter = new Person('Peter', 25) // ReferenceError: Person is not defined
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
let John = new Person('John', 25);
console.log(John) // Person { name: 'John', age: 25 }
作者:哎嘿咬我呀 链接:https://juejin.cn/post/6844903895341219854 来源:稀土掘金