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。
相关推荐
夏幻灵6 小时前
JavaScript this 面试:五种绑定规则、优先级与常见面试陷阱
开发语言·javascript·面试
三天不学习6 小时前
Egg.js 4 突然爆火,原因是否归结于AI 原生落地需求爆发?
前端·javascript·全栈·egg.js
xcs194057 小时前
前端 vue 的前端页面debugger 进不去
前端·javascript·vue.js
小宋102112 小时前
A2UI从零实战:Agent安全生成交互界面与事件回传
javascript·人工智能·安全·交互
大包子13 小时前
structuredClone vs lodash.cloneDeep:核心差异与选型指南
javascript·vue.js
lerhxx13 小时前
AI 应用中的上下文管理 —— 从"上下文窗口"到"分层压缩"的工程实践
前端·javascript
Mahut13 小时前
我在 Mac 上做了个本地剪辑器
javascript·架构·产品
汉堡大王952714 小时前
GPT-6 上线 48 小时,我扒开了 Intelligent UI 的运行机制:DIL、沙箱 Worker 和一个 React 式协调器
前端·javascript·后端
hai_android14 小时前
Chat 聊天模块功能总结
前端·javascript·vue.js
创世虚拟世界14 小时前
我做了一个 3D 虚拟世界基底,基于这个再做 3D 虚拟世界或者元宇宙,会事半功倍
javascript·人工智能·3d·gitee·虚拟现实