从零学 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,更能写出更清晰、更安全的代码。

相关推荐
猫猫不是喵喵.1 小时前
Vue3 Props 属性
前端·javascript·vue.js
jarvisuni5 小时前
DeepSeekFlash前端依旧拉垮,而且变慢了很多!
前端·javascript·算法
破z晓7 小时前
javascript 导出excel表
开发语言·javascript·excel
小罗水8 小时前
第17章 后台管理端与演示支持
javascript·vue.js·ecmascript
万少10 小时前
DeepSeek-V4-Flash 正式版上线了,但这 3 个坑我帮你提前踩了
前端·javascript·后端
宁风NF10 小时前
JavaScript:网络请求与前端通信
开发语言·前端·javascript·网络·学习·ecmascript
吾儿良辰10 小时前
Flutter 迎来重大变革:Material 设计系统拆分,迈向更开放的 UI 框架
javascript·flutter·ui
猫猫不是喵喵.11 小时前
Vue3 中 computed 计算属性与 watch、watchEffect 监听
前端·javascript·vue.js
猫猫不是喵喵.12 小时前
Vue2 的 Vuex 状态管理与 Vue3 的 Pinia 状态管理
前端·javascript·vue.js
看昭奚恤哭12 小时前
Flutter 布局核心思想
开发语言·javascript·flutter