Javascript's Hoisting(变量提升、函数提升、类提升)
Function hoisting
const callerArrow = () => {
return callee(); // 刚定义这个函数时,callee 的状态是:defined but uninitialized
// 只要 callee 在调用这个函数之前初始化了就没有问题
};
// callee(); // 见不到定义,调用会出错
const callee = () => {
console.log("Hello from callee!")
};
callerArrow(); // callee 的定义出现了,可以调用
calleeRegular();
function calleeRegular() {
console.log("Hello from calleeRegular!")
}
在同一个词法定义域中的所有声明都是能被看见的。但如果声明是函数,则还能支持直接(向后)调用,即函数提升规则。如果是箭头函数,则只能引用,不能调用。
为什么箭头函数和普通函数有这样的区别?因为箭头函数没有用到 function 关键字,是按照变量的方式来定义的,遵循的是变量提升规则。
Variable hoisting
console.log(a)
a = 1
尝试修改第二行:
定义方式 | 作用域 | hoisting? | 程序执行结果 |
---|---|---|---|
a = 1 | 全局 | 无 | ReferenceError: a is not defined |
var a = 1 | 局部 | 有 | 打印 undefined (因为 var 变量有默认值) |
let = 1 | 局部 | 有 | ReferenceError: Cannot access 'a' before initialization |
const = 1 | 局部 | 有 | ReferenceError: Cannot access 'a' before initialization |
Class hoisting
const Dog = new Animal("Bingo")
// ReferenceError: Cannot access 'Animal' before initialization
class Animal {
constructor(name) {
this.name = name
}
}
和用 const
定义的变量的提升规则一样。
总结
提升能工作是因为解释器能看到对应的声明。如果是普通函数,能直接调用;如果是 var
声明的变量,在初始化时使用默认值 undefined
。