从 var 到 let/const:JavaScript 变量声明的进化之路

varlet/const:JavaScript 变量声明的进化之路

JavaScript 最初设计于 1995 年,仅用 10 天完成原型。早期的 JS 主要用于网页简单的交互(如表单验证、动态显示),功能简单,语言设计也存在诸多"缺陷"或"不合理之处"。Douglas Crockford 在其著作《JavaScript: The Good Parts》中曾将 JS 分为三部分:

  • The Good(好的部分)
  • The Bad Parts(糟粕)
  • The Awful(极差的部分)

其中,var 的变量提升就被归为"Bad Parts"之一。

随着 ES6(ECMAScript 2015)的发布,JavaScript 正式迈向现代化,引入了 letconst,解决了 var 带来的诸多问题,使 JS 更适合大型项目和企业级开发。

本文将带你深入理解:

  • var 的缺陷:变量提升与作用域问题
  • letconst 的优势
  • 暂时性死区(Temporal Dead Zone)
  • 常量与对象冻结
  • 块级作用域的重要性

一、var:曾经的唯一选择,如今的"历史遗留"

在 ES6 之前,JavaScript 唯一的变量声明方式是 var

ini 复制代码
var age = 18;
age++;
var PI = 3.1415926; // 约定大写表示"常量",但实际可变
console.log(age);   // 19
PI = 3.15;
console.log(PI);    // 3.15 ------ 居然可以修改!

虽然我们习惯用大写字母命名"不应改变"的值(如 PI),但这只是编程约定 ,JavaScript 并不强制。这意味着 var 无法真正声明"常量"。

var 的两大问题

1. 变量提升(Hoisting)

JS 是解释型脚本语言,但也有"编译阶段" ------ 在代码执行前的一瞬间,JS 引擎会扫描所有 var 声明,并将其"提升"到当前作用域顶部。

ini 复制代码
console.log(age); // undefined
var age = 18;

这段代码的执行过程实际上是:

ini 复制代码
var age;        // 提升声明
console.log(age); // undefined(未赋值)
age = 18;       // 执行赋值

变量被"提前访问",但值是 undefined,容易引发难以排查的 bug。

2. 缺乏块级作用域

var 只有函数作用域和全局作用域,不支持块级作用域({})。

ini 复制代码
{
    var age = 18;
    let height = 188;
}
console.log(age);    // 18 ------ var 跨出了块
console.log(height); // ReferenceError: height is not defined

这导致在 for 循环、if 判断等块中声明的 var 变量会"泄露"到外部,破坏代码的封装性。


二、ES6 的救赎:letconst

ES6(2015 年发布)为 JavaScript 带来了现代化语法,其中最重要的改进之一就是引入了 letconst

✅ 推荐:从此告别 var,使用 letconst

ini 复制代码
let height = 188;
height++; // 允许修改
console.log(height); // 189

const key = 'abc123';
key = 'abc1234'; // TypeError: Assignment to constant variable.
  • let:声明可变变量
  • const:声明常量(一旦赋值不可重新赋值)

💡 最佳实践:默认使用 const,只有需要重新赋值时才用 let


三、let/const 的核心优势

1. 消除变量提升:引入"暂时性死区"(Temporal Dead Zone)

letconst 不会像 var 那样提升到作用域顶部。在声明之前访问它们会抛出错误。

ini 复制代码
console.log(height); // ReferenceError: Cannot access 'height' before initialization
let height = 188;

这个从作用域开始到变量声明之间的区域,被称为"暂时性死区"(TDZ)。它强制开发者遵循"先声明后使用"的逻辑,提高了代码的可读性和安全性。

2. 支持块级作用域

letconst{} 块内声明时,只在该块内有效。

ini 复制代码
{
    let height = 188;
    var age = 18;
}
console.log(age);    // 18
console.log(height); // ReferenceError: height is not defined

这使得变量的作用范围更加精确,避免了命名冲突,是大型项目中模块化开发的基础。


四、const 的真相:不是"值不可变",而是"引用不可变"

很多初学者误以为 const 声明的变量完全不能修改。其实,const 保证的是变量绑定的引用地址不能改变 ,但引用内部的内容可以修改

ini 复制代码
const person = {
    name: "yxw",
    age: 28
};

// person = "hahaha"; // ❌ 报错:Cannot assign to const variable
person.age = 21; // ✅ 允许:修改对象内部属性
console.log(person); // { name: "yxw", age: 21 }
如何让对象真正"不可变"?

使用 Object.freeze() 冻结对象:

ini 复制代码
const wes = Object.freeze(person);
wes.age = 17; // ❌ 在严格模式下会报错,非严格模式静默失败
console.log(wes); // 仍然是 { name: "yxw", age: 21 }

Object.freeze() 可以防止对象属性被添加、删除或修改,实现真正的不可变性(shallow freeze,浅冻结)。


五、函数提升 vs 变量提升

JavaScript 中,函数是一等公民,函数声明也会被提升。

scss 复制代码
setWidth(); // ✅ 正常执行
function setWidth() {
    var width = 100;
    console.log(width);
}

函数提升与 var 不同:函数声明会连同函数体一起提升 ,而 var 只提升声明,不提升赋值。

但注意:函数表达式不会完全提升:

scss 复制代码
getLength(); // ❌ TypeError: getLength is not a function
var getLength = function() {
    console.log(100);
};

六、常见错误汇总

错误类型 示例 原因
ReferenceError: height is not defined 在作用域外访问 let/const 变量 超出作用域范围
TypeError: Assignment to constant variable 修改 const 声明的变量 const 不允许重新赋值
ReferenceError: Cannot access 'height' before initialization let/const 声明前访问 暂时性死区(TDZ)

七、总结:现代 JavaScript 变量声明的最佳实践

特性 var let const
支持块级作用域
变量提升 ✅(声明提升) ❌(TDZ) ❌(TDZ)
可重新赋值
推荐使用 ❌(废弃) ✅(可变变量) ✅✅✅(默认选择)

✅ 使用建议:

  1. 永远不要再使用 var,它是历史的糟粕。
  2. 优先使用 const ,只有需要重新赋值时才用 let
  3. 理解暂时性死区,避免在声明前访问变量。
  4. Object.freeze() 实现对象不可变,提升数据安全性。
  5. 利用块级作用域,让变量生命周期更清晰。

结语

varlet/const,不仅是语法的更新,更是 JavaScript 语言成熟化的标志。它让 JS 从"网页脚本语言"蜕变为支持大型项目、企业级开发的现代化编程语言。

"好的代码,始于正确的变量声明。"

------ 每一位现代 JavaScript 开发者

现在,就从你的下一个项目开始,彻底告别 var,拥抱 letconst 吧!


📌 附录:快速对照表

场景 推荐写法
声明一个会变化的变量 let count = 0;
声明一个常量(如配置、ID) const API_KEY = 'xxx';
声明一个不可变对象 const config = Object.freeze({...});
避免变量提升陷阱 使用 let/const,不在声明前访问

相关推荐
十年_H3 小时前
Cesium自定义着色器-片元着色器数据来源
javascript·cesium
UIUV3 小时前
var、let 与 const:JavaScript 变量声明的演进与最佳实践
javascript
阿珊和她的猫4 小时前
深入剖析 Vue Router History 路由刷新页面 404 问题:原因与解决之道
前端·javascript·vue.js
web打印社区13 小时前
使用React如何静默打印页面:完整的前端打印解决方案
前端·javascript·vue.js·react.js·pdf·1024程序员节
YiHanXii15 小时前
this 输出题
前端·javascript·1024程序员节
维他命Coco15 小时前
js常见开发学习
javascript
!win !16 小时前
分享二个实用正则
javascript·正则表达式
xw516 小时前
分享二个实用正则
javascript·正则表达式
刘新明198916 小时前
算法还原案例4-OLLVM_MD5
开发语言·前端·javascript·1024程序员节