JavaScript:在ES6以后 var、let、const三者使用场景及建议

2 阅读4分钟

深入理解 ES6 的 letconst:告别 var 的坑,拥抱现代 JavaScript

作为前端开发者,你是否曾被 var 的“奇怪行为”折磨得怀疑人生?从 ES6(2015)开始,letconst 已成为现代 JavaScript 的标配。本文用真实代码+错误分析,带你彻底告别 var 的坑,写出更安全、可读性更高的代码。


一、var:历史的包袱,必须淘汰的“糟粕”

为什么说 var 是“坏”的?
它存在两个致命问题:变量提升函数作用域,导致代码逻辑混乱。

1. 变量提升(Hoisting)—— 编译阶段的“迷惑行为”

console.log(a); // 输出: undefined (不是报错!)
var a = 10;
  • 编译阶段var 声明被提升到作用域顶部(但只提升声明,不提升赋值)。
  • 执行阶段:赋值才发生。
  • 后果:代码逻辑“反直觉”,提前访问变量返回 undefined,容易引发 bug。

💡 举个栗子:

console.log(age); // undefined
var age = 18; 

2. 作用域问题—— 无块级作用域

if (true) {
  var name = "Tom";
}
console.log(name); // "Tom" —— 本应只在 if 块内生效!
  • var 作用域是函数级(Function Scope),而非块级(Block Scope)。
  • 在大型项目中,变量污染(变量意外覆盖)是高频问题。

结论ES5 时代,var 是唯一选择;但 ES6 之后,它已成为历史包袱,务必淘汰。


二、let:ES6 的“块级作用域”救星

核心特性:块级作用域 + 暂时性死区(TDZ)

{
  let height = 188;
  console.log(height); // 188
}
console.log(height); // ReferenceError: height is not defined

为什么 let 更安全?

  1. 块级作用域
    let 声明的变量只在当前块{})内有效,彻底解决作用域污染问题。

    for (let i = 0; i < 5; i++) {
      // i 仅在 for 块内有效
    }
    console.log(i); // ReferenceError: i is not defined
    
  2. 暂时性死区(TDZ)
    在声明前访问 let 变量,会立即报错!

    console.log(height); // ReferenceError: Cannot access 'height' before initialization
    let height = 188;
    
    • 编译阶段:变量被标记为“TDZ”(暂时性死区)。
    • 执行阶段:只有到达 let height = 188; 才激活。
    • 作用:杜绝“变量提升”带来的逻辑陷阱。

💡 关键对比

特性varlet
作用域函数级块级
变量提升✅(提升声明)❌(TDZ 阻止提前访问)
重复声明✅(覆盖)❌(SyntaxError)

三、const:常量的正确打开方式

核心特性:块级作用域 + 不可变引用

const PI = 3.1415926;
PI = 3.14; // TypeError: Assignment to constant variable.

重点: “常量” ≠ “不可变”

  • 简单类型string, number, boolean):值不可变

    const name = "Alice";
    name = "Bob"; // TypeError
    
  • 复杂类型object, array):引用地址不可变,但内部属性可变

    const person = { name: "Tom", age: 25 };
    person.age = 26; // ✅ 允许!
    person = { name: "Jerry" }; // TypeError: Assignment to constant variable.
    

如何实现“完全冻结”?

const person = { name: "Tom", age: 25 };
const frozenPerson = Object.freeze(person); // 深度冻结对象
frozenPerson.age = 26; // ❌ 无效(严格模式下会报错)

💡 最佳实践

  • 优先用 const 声明变量(除非需要修改)。
  • Object.freeze 确保对象不可变。

四、常见错误 & 解决方案(附代码)

错误信息原因解决方案
ReferenceError: height is not defined作用域外访问 let/const检查变量声明位置,确保在作用域内
TypeError: Assignment to constant variable尝试修改 const 变量改用 let 或检查是否误用 const
ReferenceError: Cannot access 'PI' before initialization提前访问 let/const(TDZ)将变量声明移到使用位置之前

正确写法

// 错误:提前访问
console.log(PI); // ❌ 报错
const PI = 3.14;

// 正确:声明在前
const PI = 3.14;
console.log(PI); // ✅ 3.14

五、为什么必须放弃 var?—— 现代 JavaScript 的最佳实践

  1. var 无处不在的坑

    • 作用域污染(for 循环中 var i 导致闭包问题)。
    • 变量提升导致逻辑混乱(console.log(a); var a = 1;)。
  2. let/const 的优势

    • 可读性:变量作用域清晰,一眼定位。
    • 安全性:TDZ 阻止“提前访问”,const 防止意外修改。
    • 工程化:大型项目中减少 bug,提升协作效率。

🚫 淘汰 var 的理由

“ES5 时代 var 是唯一选择,但 ES6 之后,var 只是历史的尘埃。—— 《JavaScript 语言精粹》”


六、结论:从现在开始尽量只用 letconst

场景推荐用法说明
变量值可能变化let例如:循环计数器、状态变量
常量(值永不变化)const例如:PI、API 地址
需要完全不可变的对象const + Object.freeze例如:配置对象

  • var → 99% 的场景都该淘汰
  • const 是默认选择,除非明确需要修改变量。
  • letconst 的补充,用于需要修改的场景。

附:ES6 语法对比速查表

语法作用域提升重复声明适用场景
var函数级❌ 历史遗留,禁用
let块级需要修改的变量
const块级常量(值不变)

“在 JavaScript 中,letconst 不是语法糖,而是语言设计的进化。用它们写代码,你会感觉像在用 Java/C++ 一样安全。” —— 《JavaScript 高级程序设计》