从零学 JavaScript:彻底搞懂 var、let、const(上篇)——告别变量提升的坑

前言:为什么你必须重新理解 JavaScript 的变量声明?

你是否曾遇到过这样的困惑?

js 复制代码
console.log(age); // 输出 undefined,而不是报错?
var age = 18;

console.log(height); // 直接报错!
let height = 1.88;

明明都是声明变量,为什么 varlet 的行为完全不同?

为什么 const 声明的"常量"对象,属性还能改?

如果你也曾被这些问题困扰,那么恭喜你,你即将揭开 JavaScript 中最经典、最易错的一块拼图:varletconst 的本质区别


一、早期 JavaScript:var 的"糟粕"时代

在 ES6(2015 年)之前,JavaScript 只有一个关键字来声明变量:var

js 复制代码
var age = 18;

var 的设计存在严重问题,最典型的就是 变量提升(Hoisting)

什么是变量提升?

JavaScript 的执行分为两个阶段:

  1. 编译阶段 :检查语法,提升 var 和函数声明
  2. 执行阶段:逐行执行代码

var 声明的变量会在编译阶段就被提升到作用域顶部,但赋值仍然留在原地。

实例说明:

js 复制代码
console.log(age); // 输出:undefined
var age = 18;
console.log(age); // 输出:18

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

js 复制代码
// 编译阶段:var age 被提升
var age; // 此时 age = undefined

// 执行阶段:
console.log(age); // undefined
age = 18;
console.log(age); // 18

这种行为完全违背直觉:还没声明就能访问,但值却是 undefined


⚠️ 二、var 的三大"坏味道"

1. 变量提升导致逻辑混乱

js 复制代码
function example() {
  console.log(a); // undefined
  var a = 10;
}

你本意是先声明再使用,但 JavaScript 却允许你在声明前访问,只是值为 undefined。这极易导致 bug。

2. 不支持块级作用域

js 复制代码
if (true) {
  var age = 18;
}
console.log(age); // 18!竟然能访问到

iffor 等块级作用域中声明的 var 变量,会泄露到外部作用域。这在大型项目中非常危险。

3. 没有常量的概念

js 复制代码
var PI = 3.1415926;
PI = 3.14; // 竟然可以修改!

虽然开发者约定"大写字母命名表示常量",但 JavaScript 本身不强制,容易被误改。


三、ES6 的救赎:letconst

2015 年,ES6 正式发布,带来了 letconst,彻底解决了 var 的问题。

let:现代变量声明的首选

js 复制代码
let height = 1.88;
height++; // 可以修改

let 的特点:

  • 不提升:不能在声明前访问
  • 支持块级作用域 :只在 {} 内有效
  • 不允许重复声明

实例对比:

js 复制代码
// var 的问题
console.log(age); // undefined
var age = 18;

// let 的正确行为
console.log(height); // 报错!Cannot access 'height' before initialization
let height = 1.88;

const:真正的常量

js 复制代码
const PI = 3.1415926;
PI = 3.14; // 报错!Assignment to constant variable.

const 声明的变量一旦赋值就不能再修改 ,否则会抛出 TypeError

注意:const 保证的是引用地址不变,而不是值不可变。


四、常见的错误与报错解析

1. ReferenceError: height is not defined

js 复制代码
console.log(height); // 报错

原因:变量 height 根本不存在,或在作用域外访问。

2. TypeError: Assignment to constant variable.

js 复制代码
const PI = 3.14;
PI = 3.15; // 报错

原因:尝试修改 const 声明的变量。

3. ReferenceError: Cannot access 'PI' before initialization

js 复制代码
console.log(PI);
const PI = 3.14; // 报错

原因:constlet 存在暂时性死区(Temporal Dead Zone),不能在声明前访问。


五、暂时性死区:letconst 的安全机制

"暂时性死区"听起来很玄乎,其实很简单:

从进入作用域到变量声明完成之前,该变量都不可访问。

示例:

js 复制代码
{
  console.log(a); // 报错!TDZ
  let a = 10;
}

这与 var 的"提升但值为 undefined"完全不同,它强制你先声明再使用,提高了代码的可读性和安全性。


六、最佳实践建议

场景 推荐使用
普通变量 let
不会重新赋值的变量 const
不再使用 var

建议:从今天起,彻底告别 var,全面使用 letconst


JavaScript 正在变得越来越"严谨"

var 是 JavaScript 早期设计不完善的产物,而 letconst 的出现,标志着 JavaScript 正在向更严谨、更适合大型项目开发的语言演进。

理解它们的区别,不仅能避免常见 bug,更能写出更清晰、更安全的代码。

相关推荐
不一样的少年_18 小时前
WebTab等插件出事后:不到100行代码,带你做一个干净透明的新标签页
前端·javascript·浏览器
幸运小圣18 小时前
关于Vue 3 <script setup> defineXXX API 总结
前端·javascript·vue.js
AAA阿giao18 小时前
从零开始:用 Vue 3 + Vite 打造一个支持流式输出的 AI 聊天界面
前端·javascript·vue.js
悦来客栈的老板18 小时前
AST反混淆实战|reese84_jsvmp反编译前的优化处理
java·前端·javascript·数据库·算法
爱看书的小沐18 小时前
【小沐学WebGIS】基于Cesium.JS绘制雷达波束/几何体/传感器Sensor(Cesium / vue / react )
javascript·vue.js·react.js·雷达·cesium·传感器·波束
zlpzlpzyd19 小时前
vue.js是干什么的?各个版本有什么区别?
前端·javascript·vue.js
被考核重击19 小时前
【无标题】
前端·javascript·vue.js
Glommer19 小时前
Akamai 逆向思路
javascript·爬虫·逆向
izx88819 小时前
从 Buffer 到响应式流:Vue3 实现 AI 流式输出的完整实践
javascript·vue.js·人工智能
幸运小圣19 小时前
动态组件【vue3实战详解】
前端·javascript·vue.js·typescript