核心结论:
变量提升和函数提升是JavaScript在编译阶段将声明移动到当前作用域顶部的机制。其中函数提升只发生在函数声明上,且优先级高于变量提升;而函数表达式(包括箭头函数)不存在函数提升。
一、函数声明 vs 函数表达式
1. 函数声明(Function Declaration)
function sum(a, b) {
return a + b;
}
2. 函数表达式(Function Expression)
// 方式1:匿名函数赋值给变量
const multiply = function(a, b) {
return a * b;
};
// 方式2:具名函数表达式(函数名只在函数内部可用)
const divide = function div(a, b) {
return a / b;
};
// 方式3:箭头函数(ES6,属于函数表达式的一种)
const subtract = (a, b) => a - b;
| 维度 | 函数声明 | 函数表达式 |
|---|---|---|
| 提升行为 | 函数体完整提升 | 只提升变量名(值仍是 undefined) |
| 调用时机 | 可在声明前调用 | 只能在声明后调用 |
| 语法形式 | function name() {} | const/let/var name = function() {} |
| 是否匿名 | 必须有函数名 | 可以匿名 |
| 块级作用域 | 不遵守(会提升到函数/全局) | 遵守(let/const 块级) |
二、变量提升
什么是变量提升?
变量提升是指 var 声明的变量在编译阶段被提升到作用域顶部,初始化为 undefined,赋值留在原地。
console.log(a); // undefined(不会报错)
var a = 10;
console.log(a); // 10
// 解释:上面代码实际执行顺序:
var a; // 提升到顶部,初始化为 undefined
console.log(a); // undefined
a = 10; // 赋值留在原地
console.log(a); // 10
可以简单理解,变量提升相当于把声明并赋值的语句,拆分为声明变量和赋值操作,并给变量一个初始值:undefined。
更专业的说法是:使用 var 声明的变量,会在编译阶段被提升到当前作用域的顶部,但赋值操作留在原地。初始值为 undefined。
let 和 const 也存在声明提升,但与 var 不同,它们不会被初始化为 undefined。从进入作用域到声明语句之间,变量处于暂时性死区(Temporal Dead Zone, TDZ),此处访问会抛出 ReferenceError,这更符合现代 JavaScript 开发的最佳实践。
console.log(b); // ❌ ReferenceError: Cannot access 'b' before initialization
let b = 20;

解释完变量提升我们来看几道题:
问题一:
(function() {
var x=foo();
var foo=function foo() {
return "foobar"
};
return x;
})();
思考一下,上一段代码运行后输出?
问题二:
(function() {
var x = foo();
function foo() {
return "foobar"
};
return x;
})();
思考一下,上一段代码运行后输出?
先来看问题一,var会变量提升,所以代码段等价于
(function(){
var x; //undefined
var foo; //undefined
x=foo(); //注意:// 此时foo还是undefined
foo=function foo(){
return "footbar"
};
return x;
})();
当程序执行到x=foo()时,foo还是undefined,而undefined不是函数,因此尝试执行undefined(),会抛出TypeError的错误。如:

因此问题一的代码并不能顺利运行,会抛出”类型错误“的错误。
再来看看问题二,var会变量提升,所以代码段等价于
(function() {
var x; //undefined
x = foo(); //可以直接调用
function foo() { //函数声明会完整提升
return "foobar"
};
return x; //返回“footbar"
})();
当程序执行到x=foo()时,此时foo是一个函数声明,可以整体提升(涉及到函数提升了),立即执行foo,返回”footbar"。
三、函数提升
学习函数提升之前需要弄清”函数声明“和”函数表达式“的定义。(前面讲过了,这里不再赘述)
函数提升只发生在【函数声明】上,【函数表达式】不存在真正意义上的函数提升。
函数声明 --> 有提升
foo(); //打印 “声明提升”
function foo(){
console.log("声明提升");
}
函数表达式 --> 无函数提升
bar(); //TypeError:bar is not a function
var bar=function (){
console.log("表达式");
};
函数表达式就是赋值函数,所以这里本质遵循var的变量提升,提升的是var bar,并给初始值为undefined。bar()会尝试执行undefined(),抛出TypeError的错误。
在看看下面的代码段,运行之后输出的是?
console.log(typeof foo); //打印foo的类型
console.log(foo);
var foo = "hello";
function foo() {
return "world";
}
该代码段既有变量提升,又有函数提升,我们来看看实际运行结果:

这是因为 当同名时,函数提升的优先级高于变量提升!

3081

被折叠的 条评论
为什么被折叠?



