像专业人士一样理解 Scope、Hoisting 和 Closures!
Source: Dev.to

什么是作用域?
作用域定义了代码中变量的可访问性。
作用域决定了变量在代码中的使用位置。
在 JavaScript 中,每个变量都有一个“边界”。在该边界之外,变量不可用。
为什么作用域重要?
- 防止变量冲突
- 高效管理内存
- 使代码行为可预测
主要的作用域类型
- 全局作用域 – 在任何地方都可访问
- 函数作用域 – 仅在函数内部可访问
- 块级作用域 – 在
{}内部可访问(使用let或const) - 词法作用域 – 由代码的书写结构决定
作用域示例
let person = [1,2,3,4,5]; // global scope
function total(num1, num2) {
const result = num1 + num2; // function scope
if (true) {
var result1 = num1 * num2; // function scope (var)
}
console.log(result1); // accessible
console.log(person); // global access
}
total(10, 20);
console.log(result); // ❌ Error, function scope要点
result在函数外不可访问。result1在函数内部可访问,因为var是函数作用域。
什么是提升?
提升是 JavaScript 的一种行为,变量和函数声明在执行阶段开始时被移动到内存中。
换句话说
在代码运行之前,JS 为所有声明的变量和函数准备内存。
重要点
var→ 被提升并初始化为undefinedlet/const→ 被提升但未初始化(它们处于暂时性死区)- 函数声明 → 完全提升
常见误解
提升并不是把代码字面上移动到顶部;它是一个内存准备过程。
提升示例
console.log(a); // undefined
var a = 10;内部,JavaScript 将其解释为:
var a;
console.log(a); // undefined
a = 10;使用 let 或 const
console.log(b); // ❌ ReferenceError
let b = 10;出现此错误是因为 let/const 被提升但未初始化,导致出现暂时性死区(TDZ)。
什么是闭包?
闭包是指函数即使在外层函数执行完毕后,仍然“记住”其外部作用域中的变量。
简而言之:函数 + 它的外围环境 = 闭包
为什么闭包有用
- 维护私有数据
- 在函数调用之间保持状态
- 在实际的 JavaScript 中被广泛使用(事件处理器、React Hook 等)
闭包示例
function total() {
let counter = 0;
return function() {
counter++;
console.log(counter);
};
}
// Usage:
const result1 = total();
result1(); // 1
result1(); // 2
const result2 = total();
result2(); // 1
result1(); // 3关键点
counter不是全局变量。- 内部函数记住了它的值。
- 每次调用
total()都会创建一个新的内存实例。
词法作用域(闭包的支柱)
function outer() {
let a = 10;
return function inner() {
console.log(a);
};
}内部函数在外部函数内部声明,因此它可以访问变量 a。这就是词法作用域,使得闭包能够工作。
这些概念如何关联
- 作用域 → 定义变量所在的位置。
- 词法作用域 → 根据代码定义函数可以访问哪些变量。
- 闭包 → 使函数能够“记住”外部作用域中的变量。
这三者在 JavaScript 中协同工作!
Summary
- Scope → 变量边界。
- Hoisting → 执行前的内存准备。
- Lexical Scope → 根据代码结构决定访问权限。
- Closure → 函数记住外部数据。
Final Thought
许多 JavaScript 中的意外行为是因为这些概念不清晰。
一旦理解了作用域、提升、词法作用域和闭包,JavaScript 就会变得可预测且更容易使用。
Tags: #webdevelopment #frontend #closure #hoisting #scope #lexicalscope #learntocode