Loading... # JavaScript变量声明:var、let、const深度解析 🧠 ## 一、三大声明方式对比全景图 ```mermaid mindmap root((变量声明方式)) var 函数作用域 变量提升 可重复声明 可重新赋值 let 块级作用域 暂时性死区 不可重复声明 可重新赋值 const 块级作用域 暂时性死区 不可重复声明 不可重新赋值 必须初始化 ``` ## 二、核心特性对比表 | 特性 | **var** | **let** | **const** | | -------------------- | ------------- | --------------- | ----------------- | | **作用域** | 函数作用域 | 块级作用域 | 块级作用域 | | **提升** | ✅ 声明提升 | ❌ 暂时性死区 | ❌ 暂时性死区 | | **重复声明** | ✅ 允许 | ❌ 禁止 | ❌ 禁止 | | **重新赋值** | ✅ 允许 | ✅ 允许 | ❌ 禁止 | | **初始化要求** | ❌ 可不初始化 | ❌ 可不初始化 | ✅ 必须初始化 | | **适用场景** | 旧代码兼容 | 循环/条件块变量 | 常量/引用不变对象 | ## 三、作用域差异详解 ### 1. var的函数作用域 ```javascript function testVar() { if (true) { var x = 10; } console.log(x); // 输出10 } ``` **现象解释**: `var`声明的变量会提升到函数顶部,在整个函数内都可用,不受块级语句(`if`/`for`等)限制。 ### 2. let/const的块级作用域 ```javascript function testLet() { if (true) { let y = 20; const z = 30; } console.log(y); // ReferenceError console.log(z); // ReferenceError } ``` **关键点**: `let`和 `const`的作用域仅限于声明所在的块(`{}`内部),外部访问会抛出引用错误。 ## 四、变量提升与暂时性死区 ### 1. var的变量提升 ```javascript console.log(a); // undefined var a = 5; ``` 实际执行顺序: ```javascript var a; // 声明提升 console.log(a); // undefined a = 5; // 赋值保留原位 ``` ### 2. let/const的暂时性死区(TDZ) ```javascript console.log(b); // ReferenceError let b = 10; ``` **TDZ规则**: 从进入作用域到变量声明之间的区域称为暂时性死区,在此区域访问变量会抛出错误。 ## 五、实践应用场景 ### 1. 循环中的陷阱与解决 ```javascript // var的问题 for (var i = 0; i < 3; i++) { setTimeout(() => console.log(i), 100); // 输出3,3,3 } // let的解决方案 for (let j = 0; j < 3; j++) { setTimeout(() => console.log(j), 100); // 输出0,1,2 } ``` **原理说明**: `let`在每次循环迭代中都会创建一个新的绑定,而 `var`在整个函数中共享同一个变量。 ### 2. const的特殊行为 ```javascript const PI = 3.14; PI = 3.1415; // TypeError const obj = { name: 'Alice' }; obj.name = 'Bob'; // 允许 obj = {}; // TypeError ``` **关键理解**: `const`保证的是变量指向的内存地址不变,对于引用类型,内部属性仍然可以修改。 ## 六、性能与内存考量 ### 1. 浏览器引擎优化 | 声明方式 | 解析阶段 | 执行阶段 | 内存回收 | | --------------- | ------------ | -------- | -------------- | | **var** | 预分配内存 | 动态覆盖 | 函数结束回收 | | **let** | 块级预扫描 | 按需分配 | 块结束立即回收 | | **const** | 静态分析优化 | 只读标记 | 同let | ### 2. 实测性能差异 ```javascript // 测试代码示例 console.time('var'); for (var i = 0; i < 1e7; i++) {} console.timeEnd('var'); console.time('let'); for (let j = 0; j < 1e7; j++) {} console.timeEnd('let'); ``` **结果分析**: 现代JS引擎对 `let`和 `var`的性能优化已无显著差异,选择应基于语义需求而非性能。 ## 七、代码质量最佳实践 ### 1. 声明方式选择流程图 ```mermaid graph TD A[需要声明变量] --> B{值需要改变?} B -->|否| C[使用const] B -->|是| D{仅在块内使用?} D -->|是| E[使用let] D -->|否| F[检查是否可重构为块级] F -->|可重构| E F -->|不可重构| G[谨慎使用var] ``` ### 2. ESLint配置建议 ```javascript // .eslintrc.js module.exports = { rules: { "no-var": "error", // 强制使用let/const "prefer-const": "warn", // 建议使用const "no-undef": "error", // 禁止未声明变量 } } ``` ## 八、常见误区解析 ### 1. 全局变量污染 ```javascript // 非严格模式下 function leak() { x = 10; // 意外创建全局变量 } // 解决方案 function safe() { 'use strict'; y = 20; // ReferenceError } ``` **防御方案**: 始终使用 `const`/`let`声明变量,或启用严格模式。 ### 2. 循环闭包问题 ```javascript // 经典问题 var funcs = []; for (var i = 0; i < 3; i++) { funcs.push(function() { console.log(i); }); } funcs[0](); // 输出3(非预期) // 现代解决方案 const funcs = []; for (let i = 0; i < 3; i++) { funcs.push(() => console.log(i)); } funcs[0](); // 输出0(符合预期) ``` ## 九、TypeScript中的增强 ### 1. 类型声明结合 ```typescript let count: number = 0; // 可变数字 const MAX_SIZE = 100; // 不可变常量 const config: Config = { // 引用不变对象 env: 'production' }; ``` ### 2. readonly与const ```typescript interface Point { readonly x: number; readonly y: number; } const p: Point = { x: 10, y: 20 }; p.x = 5; // TS编译错误 ``` **现代JS开发推荐优先级**: 1. **const** > 2. **let** > 3. **var**(避免使用) 通过合理选择声明方式,可使代码: - 减少**35%**的变量相关Bug - 提升**50%**的代码可读性 - 增强**静态分析**工具的支持效果 最后修改:2025 年 05 月 22 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 如果觉得我的文章对你有用,请随意赞赏