📚 JavaScript 变量声明三剑客:`var`、`let`、`const` 学习笔记


🌟 前言:你不知道的 JavaScript 小知识,你搞明白了吗?

"JavaScript 是一门灵活的语言,但也正因为它的'宽容',埋下了许多陷阱。"

------《你不知道的 JavaScript》

你是否遇到过:

  • ❓ 为什么变量还没定义就能访问,值却是 undefined
  • ❓ 为什么 const 定义的对象,属性还能改?
  • ❓ 为什么 let 变量不能提前访问,会报 Cannot access before initialization

这些问题的背后,正是 JavaScript 变量声明机制的"暗流"------变量提升暂时性死区作用域规则

今天,我们就来揭开 varletconst 的神秘面纱,带你彻底搞懂 JavaScript 的变量声明机制。


🧩 一、JavaScript 中如何声明变量?

JavaScript 提供了三种声明变量的方式:

关键字 用途 特性
var 声明变量(ES5 及以前) ❌ 变量提升、函数作用域、可重复声明
let 声明块级变量(ES6) ✅ 块级作用域、无变量提升(有暂时性死区)、不可重复声明
const 声明常量(ES6) ✅ 块级作用域、必须初始化、不可重新赋值

💡 推荐
ES6 之后,建议不再使用 var ,优先使用 letconst


📦 二、var:被时代淘汰的"糟粕"

1. 变量提升(Hoisting)

var 声明的变量会在编译阶段被提升到作用域顶部。

ini 复制代码
javascript
编辑
console.log(age); // 输出: undefined
var age = 18;

执行过程解析:

javascript 复制代码
javascript
编辑
// 实际执行顺序(编译阶段已提升)
var age;           // 变量提升,值为 undefined
console.log(age);  // undefined
age = 18;          // 赋值

⚠️ 问题

这种"先使用后声明"的行为不符合直觉,容易导致 bug。


2. 函数提升(Function Hoisting)

函数声明也会被提升,且函数体也会被提升

scss 复制代码
javascript
编辑
setWidth(); // 正常执行

function setWidth() {
    var width = 100;
    console.log(width); // 输出: 100
}

对比:函数表达式不会完全提升

scss 复制代码
javascript
编辑
setHeight(); // TypeError: setHeight is not a function

var setHeight = function() {
    console.log(200);
};

📌 核心区别

  • function fn() {}:函数声明 → 声明 + 赋值 都提升
  • var fn = function() {}:函数表达式 → 只有声明提升

🔒 三、letconst:ES6 的救星

1. 块级作用域(Block Scope)

letconst 只在 {} 块内有效。

ini 复制代码
javascript
编辑
{
    let a = 1;
    const b = 2;
}
console.log(a); // ReferenceError: a is not defined

优势:避免变量污染全局作用域。


2. 暂时性死区(Temporal Dead Zone, TDZ)

let/const 声明之前访问变量,会报错。

ini 复制代码
javascript
编辑
console.log(PI); // ReferenceError: Cannot access 'PI' before initialization
const PI = 3.1415926;

💡 为什么设计 TDZ?

防止开发者误用"提升"特性,提高代码可读性和安全性。


3. const 的"常量"真相

const 并不意味着"值不可变",而是引用不可变

✅ 简单类型:不可修改

ini 复制代码
javascript
编辑
const key = 'abc123';
key = 'abc234'; // TypeError: Assignment to constant variable.

✅ 复杂类型:可修改属性

ini 复制代码
javascript
编辑
const person = {
    name: "ysw",
    age: 28,
};

person.age = 21; // ✅ 允许,修改的是对象内部属性
console.log(person); // { name: "ysw", age: 21 }

person = {}; // ❌ 报错,不能重新赋值

🔒 如何真正"冻结"对象?

ini 复制代码
javascript
编辑
const wes = Object.freeze(person);
wes.age = 17; // ❌ 在严格模式下报错,非严格模式静默失败
console.log(wes); // age 仍为 21

📌 Object.freeze() :浅冻结,只冻结对象自身属性,不递归冻结嵌套对象。


🧠 四、三大错误类型解析

错误 原因 示例
ReferenceError: height is not defined 变量未声明,作用域外调用 console.log(height);(未声明)
TypeError: Assignment to constant variable. 尝试修改 const 变量 const a = 1; a = 2;
ReferenceError: Cannot access 'PI' before initialization 访问了暂时性死区中的变量 console.log(PI); const PI = 3.14;

🖼️ 五、图解:变量声明机制

📌 关键记忆

  • var:提升 → 赋值 → 访问
  • let/const:提升 → TDZ → 赋值 → 访问

💼 六、大厂高频面试题(变量声明专项)

❓ Q1: varletconst 有什么区别?

参考回答

特性 var let const
作用域 函数作用域 块级作用域 块级作用域
变量提升 ❌(有 TDZ) ❌(有 TDZ)
重复声明
重新赋值

📌 总结:var 是历史遗留,let 用于变量,const 用于常量。


❓ Q2: 什么是暂时性死区(TDZ)?为什么设计它?

参考回答

暂时性死区是指 let/const 变量从作用域开始到声明语句之间的区域。在此区域内访问变量会报错。

设计目的

  1. 避免 var 提升带来的"先使用后声明"陷阱
  2. 提高代码可读性和安全性
  3. 强制开发者遵循"先声明后使用"的良好习惯

❓ Q3: const 定义的对象属性能改吗?如何真正冻结?

参考回答

可以。const 只保证引用地址不变,不保证对象内部属性不变。

使用 Object.freeze(obj) 可以冻结对象,使其属性不可修改。但它是浅冻结,嵌套对象仍可修改。

ini 复制代码
javascript
编辑
const obj = { a: { b: 1 } };
Object.freeze(obj);
obj.a.b = 2; // ✅ 仍可修改

💡 加分项:可用 deepFreeze 实现深冻结。


❓ Q4: functionvar 的提升有什么区别?

参考回答

  • var:只提升声明,不提升赋值
  • function:提升声明和函数体(函数声明)
  • 函数表达式:行为类似 var,只提升声明
scss 复制代码
javascript
编辑
foo(); // TypeError
var foo = function() {};

bar(); // 正常执行
function bar() {}

❓ Q5: 为什么建议不再使用 var

参考回答

  1. 变量提升导致"先使用后声明",易出 bug
  2. 函数作用域容易污染全局变量
  3. 可重复声明增加维护成本
  4. let/const 提供了更安全、更清晰的块级作用域

📌 现代开发应优先使用 letconst


✅ 七、总结:变量声明最佳实践

场景 推荐 说明
普通变量 let 块级作用域,安全
常量 const 防止意外修改
对象/数组 const + Object.freeze()(如需完全冻结) 保证引用和内容不变
循环变量 let 避免闭包问题
全局变量 尽量避免 使用模块化或立即执行函数

🌟 记住口诀
"能用 const 不用 let,能用 let 不用 var"
"先声明,后使用,TDZ 拒绝提前访问"


🚀 下一步

  • ✅ 实践:用 let/const 重构旧项目中的 var
  • ✅ 演练:故意触发 TDZ 错误,理解其机制
  • ✅ 进阶:学习 Object.freeze() 和深冻结实现

💡 JavaScript 的"糟粕"已被淘汰,拥抱 ES6+ 的"精华" ,写出更安全、更可维护的代码! ✨

相关推荐
可触的未来,发芽的智生4 小时前
追根索源:换不同的词嵌入(词向量生成方式不同,但词与词关系接近),会出现什么结果?
javascript·人工智能·python·神经网络·自然语言处理
努力写代码的熊大4 小时前
stack、queue与priority_queue的用法解析与模拟实现
java·前端·javascript
im_AMBER4 小时前
React 06
前端·javascript·笔记·学习·react.js·前端框架
m0_748233646 小时前
C++开发中的常用设计模式:深入解析与应用场景
javascript·c++·设计模式
fruge6 小时前
TypeScript 基础类型与接口详解
javascript·ubuntu·typescript
AAA阿giao6 小时前
JavaScript 中的变量声明:var、let 与 const 深度解析
javascript·笔记
Mintopia7 小时前
🌐 数据合规框架下的 WebAIGC 训练数据处理技术规范
前端·javascript·aigc
用户6600676685397 小时前
从 var 到 let/const:JavaScript 变量声明的进化之路
javascript
十年_H7 小时前
Cesium自定义着色器-片元着色器数据来源
javascript·cesium