像专业人士一样理解 Scope、Hoisting 和 Closures!

发布: (2026年4月5日 GMT+8 16:00)
5 分钟阅读
原文: Dev.to

Source: Dev.to

《深入理解作用域、提升和闭包的技巧》封面图片

什么是作用域?

作用域定义了代码中变量的可访问性。

作用域决定了变量在代码中的使用位置。
在 JavaScript 中,每个变量都有一个“边界”。在该边界之外,变量不可用。

为什么作用域重要?

  • 防止变量冲突
  • 高效管理内存
  • 使代码行为可预测

主要的作用域类型

  • 全局作用域 – 在任何地方都可访问
  • 函数作用域 – 仅在函数内部可访问
  • 块级作用域 – 在 {} 内部可访问(使用 letconst
  • 词法作用域 – 由代码的书写结构决定

作用域示例

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 → 被提升并初始化为 undefined
  • let / const → 被提升但未初始化(它们处于暂时性死区)
  • 函数声明 → 完全提升

常见误解

提升并不是把代码字面上移动到顶部;它是一个内存准备过程。

提升示例

console.log(a); // undefined
var a = 10;

内部,JavaScript 将其解释为:

var a;
console.log(a); // undefined
a = 10;

使用 letconst

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

0 浏览
Back to Blog

相关文章

阅读更多 »

执行上下文

想象 Execution Context 像一个厨房。在你开始烹饪(执行代码)之前,你需要工作空间、变量工具和函数配方。