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。
相关推荐
成都渲染101云渲染66662 小时前
跳出“硬件堆砌”陷阱|渲染101如何用技术重构云渲染的专业价值?
java·前端·javascript
SuperEugene2 小时前
Vue3 性能优化规范:日常必做优化(不玄学、可落地)|可维护性与兜底规范篇
开发语言·前端·javascript·vue.js·性能优化·前端框架
cypking2 小时前
二次封装ElementUI日期范围组件:打造带限制规则的Vue2 v-model响应式通用组件
前端·javascript·elementui
酉鬼女又兒2 小时前
零基础快速入门前端蓝桥杯Web考点深度解析:var、let、const与事件绑定实战(可用于备赛蓝桥杯Web应用开发)
开发语言·前端·javascript·职场和发展·蓝桥杯·es6·html5
happymaker06263 小时前
vue指令扩展以及监视器的使用
前端·javascript·vue.js
还是大剑师兰特3 小时前
EventBus核心方法用法
javascript·vue.js·大剑师
一只小阿乐3 小时前
vue前端处理流式数据
前端·javascript·ai·大模型·全栈开发·agentai
꧁꫞꯭零꯭点꯭꫞꧂3 小时前
前端面试题3
开发语言·前端·javascript
ZC跨境爬虫4 小时前
Base64编码详解(含JS_Python实现+实战逆向案例)
前端·javascript·python