作用域 变量提升(Hoisting)的代码输出题
🧩 题目 1:函数声明 vs 变量声明
console.log(a);
var a = 1;
function a() {}
console.log(a);
✅ 输出:
ƒ a() {}
1
🧠 解析:
-
函数声明 与 变量声明 都会被提升;
-
但函数声明的优先级 高于 变量声明;
-
执行顺序:
- 声明阶段:
function a() {}被提升; - 再执行
var a = 1(只是赋值,不再提升);
- 声明阶段:
-
所以第一次打印是函数,第二次打印是数值。
🧩 题目 2:函数声明在块级作用域中的提升(ES6 陷阱题)
function test() {console.log(a);if (true) {function a() {}}console.log(a);
}
test();
✅ 输出:
undefined
ƒ a() {}
🧠 解析:
- 在 ES6 之后,函数声明在块级作用域中行为有特殊规定;
- 在非严格模式下:
块级函数声明会被当作“变量声明 + 函数赋值”处理。- 函数声明会被提升到函数作用域顶部(不是块内);
- 但在声明之前访问时是
undefined;
- 因此第一次是
undefined,执行完 if 后函数可用。 - 所以内部相当于:
function test() {var a; // 提升,a = undefinedconsole.log(a); // → undefinedif (true) {a = function a() {}; // 执行到这里才赋值}console.log(a); // → ƒ a() {}
}
💡 加分点:你可以补一句
“在严格模式('use strict')下,块级函数声明不会提升,第一次会报错。”
🧩 题目 3:let 与 var 的区别(TDZ)
console.log(a);
let a = 10;
✅ 输出:
ReferenceError: Cannot access 'a' before initialization
🧠 解析:
let声明也会被“提升”(只是不会初始化);- 在声明之前访问变量会触发 暂时性死区(TDZ);
- 因此抛出
ReferenceError。
🧩 题目 4:变量提升与函数表达式
console.log(foo);
var foo = function() {console.log('bar');
}
foo();
✅ 输出:
undefined
bar
🧠 解析:
var foo声明被提升,但赋值部分不会;- 所以第一次打印
undefined; - 之后
foo被赋值为函数,执行时输出'bar'。
🧩 题目 5:变量提升与函数作用域
var a = 10;
function test() {console.log(a);var a = 20;console.log(a);
}
test();
✅ 输出:
undefined
20
🧠 解析:
-
由于 var 存在函数级作用域,
test()内部的a会被提升; -
相当于:
function test() {var a;console.log(a); // undefineda = 20;console.log(a); // 20 } -
外部
a=10被局部变量遮蔽。
🧩 题目 6:函数声明与同名变量(高频陷阱)
function foo() {console.log(a);var a = 1;console.log(a);function a() {}console.log(a);
}
foo();
✅ 输出:
ƒ a() {}
1
1
🧠 解析:
-
声明阶段:
function a() {}被提升;var a只声明不覆盖函数;
-
执行阶段:
- 第一次打印函数;
- 然后赋值
a = 1; - 后续打印都是
1。
🧩 题目 7:嵌套作用域与提升顺序
var a = 1;
function foo() {console.log(a);var a = 2;function bar() {console.log(a);}bar();
}
foo();
✅ 输出:
undefined
2
🧠 解析:
-
foo内部的var a被提升,遮蔽外层的a = 1; -
执行顺序:
- 声明阶段:
var a、function bar提升; - 执行
console.log(a)→undefined; - 赋值
a = 2; bar()打印2。
- 声明阶段:
🧠 面试技巧总结:
| 考点 | 记忆口诀 |
|---|---|
| 1️⃣ var 提升 | 声明提升,赋值不提升 |
| 2️⃣ function 提升 | 整个函数体都提升,优先级高于 var |
| 3️⃣ let / const | 有 TDZ,不可在声明前访问 |
| 4️⃣ 块级作用域 | let/const 有块级作用域,var 无 |
| 5️⃣ 同名函数/变量 | 函数声明优先于 var 声明,但不优于 var 赋值 |
