JavaScript 声明提升 (Hoisting)
JavaScript 中的 声明提升 是指变量和函数的声明会被提升到当前执行环境的顶部。这意味着,在代码的执行过程中,变量和函数的声明会在代码执行前被处理,而不管它们在代码中的具体位置。
1. 变量声明提升 (var)
在使用 var 声明变量时,JavaScript 会将变量的声明(而不是赋值)提升到当前作用域的顶部。即使变量赋值语句在后面,变量仍然会在代码的最开始处被“声明”。
示例:使用 var 进行变量声明
console.log(x); // 输出 undefined,因为 x 已被提升,但尚未赋值
var x = 5;
console.log(x); // 输出 5
解释:
- 在代码执行前,
var x;会被提升到顶部,初始化为undefined。 - 然后,
x = 5;会在原位置执行,因此第一次console.log(x)输出的是undefined,第二次输出的是5。
2. 函数声明提升
函数声明会被提升到顶部,意味着你可以在函数定义之前调用该函数。这适用于函数声明的情况,但不适用于函数表达式。
示例:函数声明提升
console.log(foo()); // 输出 "Hello!"
function foo() {
return "Hello!";
}
解释:
- 在执行代码之前,整个函数声明(
function foo() { ... })会被提升到顶部。 - 因此,即使
foo()在调用时位于函数声明之前,代码仍然能够正常工作。
3. 函数表达式不会提升
如果将函数赋值给一个变量,那么该变量的声明会被提升,但是函数的定义不会被提升。因此,在调用之前引用该函数会导致 TypeError。
示例:函数表达式不会提升
console.log(foo()); // TypeError: foo is not a function
var foo = function() {
return "Hello!";
};
解释:
var foo;会被提升,但赋值foo = function() {...}会保持原来的位置。- 由于函数表达式没有被提升,第一次调用
foo()会导致TypeError,因为在函数调用时,foo的值为undefined。
4. let 和 const 的声明提升
let 和 const 也有类似的提升行为,但它们不会被初始化。它们会进入所谓的 “暂时性死区” (TDZ),即在声明之前访问它们会导致错误。
示例:let 和 const 的提升
console.log(a); // ReferenceError: Cannot access 'a' before initialization
let a = 10;
解释:
let和const会被提升到顶部,但是它们不会初始化。在声明之前访问它们会抛出ReferenceError。- 在上面的例子中,
a被提升,但在访问a之前,它还没有初始化,导致ReferenceError。
5. 总结:提升的行为
var声明的变量会被提升到顶部,但初始化值不会被提升。变量的初始值是undefined,直到执行到赋值语句。- 函数声明会被提升到顶部,意味着你可以在函数定义之前调用它。
- 函数表达式的提升仅限于变量声明部分,函数本身不会被提升。
let和const声明的变量会被提升到顶部,但进入暂时性死区,在声明之前无法访问。
6. 示例总结
// var 变量提升
console.log(a); // undefined
var a = 2;
// 函数声明提升
console.log(foo()); // Hello!
function foo() {
return "Hello!";
}
// 函数表达式不会提升
console.log(bar()); // TypeError: bar is not a function
var bar = function() {
return "Hi!";
}
// let 和 const 提升到顶部,但有 TDZ
console.log(x); // ReferenceError: Cannot access 'x' before initialization
let x = 10;
总结
- 声明提升会将变量和函数的声明部分提升到当前作用域的顶部。
var的变量会被提升,并初始化为undefined。- 函数声明会被完全提升(包括函数体)。
let和const也会被提升,但在声明前访问它们会导致错误(ReferenceError)。- 函数表达式的赋值不会被提升,函数定义会在代码的实际位置执行。
更多详细信息请关注其他相关文章。