JS 入门通关手册(36):变量提升、暂时性死区与块级作用域

摘要

本文系统讲解 JavaScript 变量提升机制、暂时性死区(TDZ)以及 ES6 块级作用域,通过大量可运行案例清晰展示 var/let/const 在声明、提升、作用域上的差异,总结日常开发中的常见陷阱与最佳实践,帮助开发者从底层理解变量行为,避免隐性 bug,夯实前端基础。


一、变量提升:JavaScript 先 "扫描" 再执行

在 JS 执行代码前,引擎会先遍历当前作用域,把变量声明和函数声明 提升到作用域顶部,这一机制称为变量提升(Hoisting)

关键点:

  • 只提升声明,不提升赋值
  • 函数声明整体提升,可在定义前调用
  • var 变量提升为 undefined

1. var 变量提升

javascript

运行

javascript 复制代码
console.log(name); // undefined
var name = "前端开发";

// 引擎实际执行顺序
var name;
console.log(name);
name = "前端开发";

2. 函数声明提升

javascript

运行

javascript 复制代码
foo(); // 正常执行:hello

function foo() {
  console.log("hello");
}

3. 函数表达式不会提升

javascript

运行

javascript 复制代码
foo(); // TypeError: foo is not a function

var foo = function () {
  console.log("hello");
};

4. 函数提升优先级高于变量

同名情况下,函数声明会覆盖 var 声明

javascript

运行

javascript 复制代码
console.log(foo); // [Function: foo]

var foo = 123;
function foo() {}

二、let /const 也会提升,但存在暂时性死区

很多人误以为 let/const 不提升,实际上它们同样提升 ,只是进入暂时性死区(TDZ),无法提前访问。

javascript

运行

javascript 复制代码
console.log(age); 
// Uncaught ReferenceError: Cannot access 'age' before initialization

let age = 20;

什么是暂时性死区 TDZ?

从作用域开始,到变量声明语句之间的区域,就是该变量的暂时性死区。在死区内访问变量会直接报错。

javascript

运行

javascript 复制代码
{
  // 此处开始到 let num 之前都是 TDZ
  console.log(num); // 报错
  let num = 10;
  // TDZ 结束
}

经典陷阱:

javascript

运行

javascript 复制代码
let a = 1;
{
  console.log(a); // 报错!受内部 let 影响进入 TDZ
  let a = 2;
}

三、ES6 块级作用域:{} 就是一个作用域

ES6 之前只有全局作用域函数作用域 。ES6 新增块级作用域 ,由 {} 包裹,if / for / while / try 都会形成块级作用域。

let /const 具有块级作用域

javascript

运行

javascript 复制代码
{
  let name = "张三";
  const age = 20;
}
console.log(name); // ReferenceError

var 不受块级作用域限制

javascript

运行

javascript 复制代码
{
  var num = 100;
}
console.log(num); // 100,正常访问

典型场景:循环事件绑定问题

javascript

运行

javascript 复制代码
// var 会泄露,输出都是 5
for (var i = 0; i < 5; i++) {
  setTimeout(() => console.log(i), 0);
}

// let 具有块级作用域,输出 0 1 2 3 4
for (let i = 0; i < 5; i++) {
  setTimeout(() => console.log(i), 0);
}

四、var /let/const 全方位对比

表格

特性 var let const
作用域 函数 / 全局 块级 块级
变量提升 是,值为 undefined 是,但 TDZ 不可访问 是,但 TDZ 不可访问
重复声明 允许 不允许 不允许
重新赋值 支持 支持 不支持
初始赋值 非必须 非必须 必须
挂载到 window
开发推荐 不推荐 可变值使用 优先使用

五、常见面试题

  1. **变量提升是什么?为什么会出现?**答:JS 执行前会扫描作用域并提升声明,只提升声明不提升赋值,目的是为了让函数可以在定义前调用。

  2. **let 存在变量提升吗?**答:存在提升,但受暂时性死区限制,声明前访问会抛出引用错误。

  3. **const 定义的对象可以修改属性吗?**答:可以修改属性与成员,不能修改引用(重新赋值)。

  4. **暂时性死区的意义是什么?**答:强制规范变量先声明后使用,减少隐性错误,提升代码健壮性。

  5. **为什么现代项目推荐 const > let > var?**答:const 语义明确、不可变、更安全;let 避免变量污染;var 易产生提升与全局污染问题。


六、总结

  1. 变量提升是 JS 执行前的声明扫描机制,只提升声明不提升赋值。
  2. 函数声明提升优先级高于 var 变量声明。
  3. let/const 存在提升,但受暂时性死区 TDZ 保护。
  4. let/const 支持块级作用域,可有效避免变量污染与循环问题。
  5. 现代开发规范:优先使用 const,需要变化时使用 let,尽量不使用 var。
相关推荐
空中海5 小时前
第七章:vue工程化与构建工具
前端·javascript·vue.js
zhensherlock5 小时前
Protocol Launcher 系列:Trello 看板管理的协议自动化
前端·javascript·typescript·node.js·自动化·github·js
渔舟小调5 小时前
P19 | 前端加密通信层 pikachuNetwork.js 完整实现
开发语言·前端·javascript
qq_12084093716 小时前
Three.js 工程向:Draw Call 预算治理与渲染批处理实践
前端·javascript
不会聊天真君6478 小时前
JavaScript基础语法(Web前端开发笔记第三期)
前端·javascript·笔记
齐鲁大虾8 小时前
新人编程语言选择指南
javascript·c++·python·c#
码路飞9 小时前
玩了一圈 AI 编程工具,Background Agent 才是让我真正震撼的东西
前端·javascript
林恒smileZAZ9 小时前
Three.js实现更真实的3D地球[特殊字符]动态昼夜交替
开发语言·javascript·3d
月月大王的3D日记9 小时前
别再复制粘贴了,从零拆解 3D 场景的诞生过程
javascript