小Dora 的 JavaScript 修炼日记 · Day 1:变量三兄弟与作用域迷宫

"如果连变量都不懂,那你永远也不知道 JavaScript 在发什么疯。"

------ 来自一位在 TDZ 中走丢的程序员

今天是小Dora正式踏入 JavaScript 的第一天,目标明确:未来成为一名高级前端工程师。第一关,就是打通【变量声明】这座看似简单、实则杀机重重的迷宫。


🧭 一、变量三兄弟登场:varletconst

🥷 var ------ 江湖老油条,喜欢走捷径

ini 复制代码
console.log(name); // undefined
var name = "小Dora";

这不会报错,只会输出 undefined,因为 var 有个江湖绝技叫:

变量提升(Hoisting) :变量声明会被"提前"到函数顶部,但赋值不会提升。

就像你抢了考场前排的位置,但忘了带笔,系统只看到你在,但你写不出字。

ini 复制代码
var name;
console.log(name); // undefined
name = "小Dora";

特点总结:

特性 说明
✅ 提升 声明被提升,初始化不被提升
❌ 无块级作用域 {} 对它没用,只认函数作用域
✅ 可重复声明 多次声明互相覆盖也不吭声

🧑‍💼 let ------ 年轻新贵,条条框框一堆

ini 复制代码
console.log(age); // ❌ ReferenceError
let age = 18;

为啥不是 undefined?------因为你误闯了:

⚠️ 暂时性死区 TDZ(Temporary Dead Zone)

所谓 TDZ,就是变量虽然在词法上已经声明了,但在赋值之前你敢碰它,JS 就会直接朝你扔一个 ReferenceError。

javascript 复制代码
{
  // 这里进入 TDZ
  console.log(tool); // ❌ ReferenceError
  let tool = "Vue.js";
  // TDZ 结束
}

let 特性总结:

特性 说明
❌ 无提升 存在 TDZ,不允许提前访问
✅ 块级作用域 出了 {} 就再见了
❌ 不可重复声明 同一作用域声明两次就爆炸

🛡️ const ------ 永不叛变的"铁憨憨"

ini 复制代码
const mission = "成为高级前端";
mission = "成为产品经理"; // ❌ TypeError

你不能改变它指向的值,但是:

ini 复制代码
const config = { debug: true };
config.debug = false; // ✅ 可以改属性

也就是说:你不能换人,但可以给人换衣服。


🧠 二、作用域与生命周期:变量的隐形牢笼

什么是作用域?

作用域 = 变量的"活动范围"

JS 中有三种作用域:

类型 示例 说明
全局作用域 文件最外层定义 到处都能访问
函数作用域 var 定义位置 只在函数内可访问
块级作用域 let/const 定义 花括号 {} 控制访问边界

🧬 生命周期三阶段

每个变量的"人生"都有三个阶段:

阶段 内容说明
创建阶段 引擎发现变量,分配内存
初始化阶段 var 设为 undefinedlet/const 进入 TDZ
执行阶段 正式赋值、参与代码运行

例子:

ini 复制代码
function demo() {
  console.log(a); // undefined
  console.log(b); // ❌ ReferenceError
  var a = 1;
  let b = 2;
}

💻 三、实战演练:作用域对比与 TDZ 演示

1. var 穿墙术

ini 复制代码
{
  var foo = "JS Ninja";
}
console.log(foo); // ✅ JS Ninja

因为 var 无视 {},只有函数能挡住它。


2. let/const 的结界

ini 复制代码
{
  let secret = "封印之术";
}
console.log(secret); // ❌ ReferenceError

let / const{} 外全都"隐身"。


🧪 四、自测问答 · 你能拿满分吗?

✅ 快问快答题(选择题)

1. 以下哪个变量声明不会触发 ReferenceError?

A. let 声明前访问

B. var 声明前访问

C. const 声明前访问

D. 访问未定义变量 x

✅ 答案:B


2. 以下哪种行为不会引发报错?

A. let a = 1; let a = 2;

B. const x = 1; x = 2;

C. const obj = {}; obj.name = 'Dora';

D. let b; console.log(b);

✅ 答案:C


🧠 思维题(简答)

Q1:TDZ 的设计目的是什么?为什么不直接返回 undefined

🎯 答案参考:TDZ 是为了防止访问未初始化的变量。若访问未初始化变量返回 undefined,容易掩盖错误逻辑;TDZ 让错误提早暴露,增强代码健壮性。


Q2:为什么 let 在异步循环中能正确输出索引?

javascript 复制代码
for (let i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 0);
}
// 输出:0 1 2

🎯 答案参考:let 在每次循环中创建了独立作用域的 i ,每个 i 都是新的绑定,闭包捕获的是正确的值。


👨‍💻 五、大厂爱问面试题(挑战加深)

💣 面试题 1:以下代码输出什么?

ini 复制代码
function foo() {
  console.log(a); // ?
  console.log(b); // ?
  var a = 10;
  let b = 20;
}
foo();

✅ 输出:

javascript 复制代码
undefined
ReferenceError

💣 面试题 2:

ini 复制代码
{
  var a = 1;
  let b = 2;
}
console.log(a); // ?
console.log(b); // ?

✅ 输出:

javascript 复制代码
1
ReferenceError

💣 面试题 3:

ini 复制代码
const person;
person = { name: "小Dora" };

✅ 输出:SyntaxError: Missing initializer in const declaration


✅ 六、小Dora Day 1 修炼总结

特性对比 var let const
是否提升 ✅ 只提升声明 ❌(存在 TDZ) ❌(存在 TDZ)
作用域类型 函数作用域 块级作用域 块级作用域
可否重复声明 ✅ 可重复 ❌ 报错 ❌ 报错
可否重新赋值 ✅ 可以 ✅ 可以 ❌ 不可重新赋值

🔚 尾声:走出变量迷宫,踏入执行上下文

第一天结束了,小Dora已经理解:

  • 变量三兄弟不仅语法不同,运行机制也不同
  • TDZ、作用域和变量提升,是理解 JS 的起点
  • 每一个变量都有生命周期,控制它就是掌控 JS

📌 下一站:词法作用域、执行上下文与闭包三连击 ------ 这是所有中高级面试绕不过去的必杀技。

如果你也在学习 JavaScript,欢迎继续追更 《小Dora 的 JS 修炼日记》

我们不只写代码,我们要理解代码"为什么这么写"。

相关推荐
Nan_Shu_6141 分钟前
学习: Threejs (2)
前端·javascript·学习
G_G#9 分钟前
纯前端js插件实现同一浏览器控制只允许打开一个标签,处理session变更问题
前端·javascript·浏览器标签页通信·只允许一个标签页
@大迁世界24 分钟前
TypeScript 的本质并非类型,而是信任
开发语言·前端·javascript·typescript·ecmascript
GIS之路33 分钟前
GDAL 实现矢量裁剪
前端·python·信息可视化
是一个Bug37 分钟前
后端开发者视角的前端开发面试题清单(50道)
前端
Amumu1213839 分钟前
React面向组件编程
开发语言·前端·javascript
学历真的很重要39 分钟前
LangChain V1.0 Context Engineering(上下文工程)详细指南
人工智能·后端·学习·语言模型·面试·职场和发展·langchain
持续升级打怪中1 小时前
Vue3 中虚拟滚动与分页加载的实现原理与实践
前端·性能优化
GIS之路1 小时前
GDAL 实现矢量合并
前端
hxjhnct1 小时前
React useContext的缺陷
前端·react.js·前端框架