JavaScript的Hoisting(声明提升)是语言编译阶段的一个特性,指的是变量和函数的声明会在代码正式执行前被提升到当前作用域的顶部,但赋值操作并不会跟随提升。这个特性会导致一些看似不符合直觉的代码执行结果,下面我们先通过一张示意图直观了解提升的基本表现。

变量声明的提升规则
var声明的变量提升
使用var声明的变量会提升到当前函数作用域或全局作用域的顶部,同时会被初始化为undefined,直到执行到赋值语句时才会被赋予实际的值。
// var声明提升示例 console.log(a); // 输出 undefined var a = 10; console.log(a); // 输出 10 // 上面的代码实际执行逻辑等同于 var a; // 声明提升到顶部,初始化为undefined console.log(a); a = 10; // 赋值操作留在原位置 console.log(a);
let和const声明的变量提升
使用let和const声明的变量也会被提升,但是不会被初始化,在声明语句之前访问这些变量会触发暂时性死区(TDZ)错误,这也是为什么let和const不存在重复声明问题的原因之一。
// let声明提升示例 console.log(b); // 报错:Cannot access 'b' before initialization let b = 20; // const声明同理,且必须在声明时赋值 console.log(c); // 报错:Cannot access 'c' before initialization const c = 30;
函数声明的提升规则
函数声明的提升
函数声明会被整体提升到当前作用域的顶部,包括函数体,因此在函数声明之前就可以调用该函数。
// 函数声明提升示例
sayHello(); // 输出 你好,世界
function sayHello() {
console.log('你好,世界');
}
函数表达式的提升
函数表达式本质是变量赋值,提升规则遵循变量的提升规则:如果是var声明的函数表达式,变量会提升并初始化为undefined,在赋值前调用会报错;如果是let/const声明的函数表达式,同样会触发暂时性死区错误。
// var函数表达式示例
sayHi(); // 报错:sayHi is not a function
var sayHi = function() {
console.log('Hi');
};
// 上面的代码实际执行逻辑
var sayHi;
sayHi(); // 此时sayHi是undefined,不是函数,调用报错
sayHi = function() {
console.log('Hi');
};
优先级与特殊情况
当变量声明和函数声明同名时,函数声明的优先级更高,会覆盖同名的变量声明,但是变量赋值会覆盖函数声明。
// 同名声明优先级示例
console.log(foo); // 输出 [Function: foo]
var foo = '我是变量';
function foo() {
console.log('我是函数');
}
console.log(foo); // 输出 我是变量
// 实际执行逻辑
function foo() { // 函数声明先提升
console.log('我是函数');
}
var foo; // var声明提升,但是和已有函数同名,不会重复声明
console.log(foo); // 此时foo还是函数
foo = '我是变量'; // 赋值操作覆盖函数
console.log(foo); // 此时foo是字符串
Hoisting的原理说明
JavaScript引擎在执行代码前会先进行编译阶段,这个阶段会收集所有的声明(变量声明、函数声明),并把它们加入到对应的作用域中,这就是提升的本质。赋值操作属于执行阶段的代码,不会被提前处理,因此才会出现声明提前但赋值留在原位置的情况。
理解Hoisting的核心是要区分声明和赋值的执行阶段,同时掌握不同声明关键字(var/let/const)和不同函数定义方式(声明/表达式)的规则差异,这样就能准确预判代码的执行结果,避免因为提升特性导致的逻辑错误。
JavaScriptHoisting变量声明提升函数声明提升作用域修改时间:2026-06-25 00:27:14