概念

  1. 作用域(Scope)

    作用域是定义变量和函数的可见性和生命周期的规则集合。在JavaScript中,有两种主要类型的作用域:

    • 全局作用域(Global Scope):全局作用域是在整个JavaScript程序中可访问的最外层作用域。在浏览器中,全局作用域通常是指window对象。全局作用域中定义的变量和函数可以在整个程序中访问。
    • 局部作用域(Local Scope):局部作用域是在函数内部定义的作用域,它仅在函数内部可访问。这意味着在函数外部无法访问函数内部的变量,但在函数内部可以访问外部作用域(包括全局作用域)的变量。
  2. 作用域链(Scope Chain)

    作用域链是一种用于查找变量和函数的机制,它是由嵌套的作用域构成的链条。当在某个作用域中引用一个变量或函数时,JavaScript引擎会首先在当前作用域中查找,如果找不到,就会沿着作用域链向外层作用域查找,直到找到匹配的变量或函数或达到全局作用域为止。

    这个过程确保了内部作用域可以访问外部作用域的变量,但外部作用域无法访问内部作用域的变量。这种嵌套的作用域链使得变量名可以在不同的作用域中重复使用而不会发生冲突。

作用域的分类

  1. 全局作用域

    在全局作用域中声明的变量可以在整个程序中访问。

    1
    2
    3
    4
    5
    6
    7
    8
    var globalVar = "I'm global"; // 全局作用域

    function globalFunction() {
    console.log(globalVar); // 可以在函数中访问全局变量
    }

    globalFunction();
    console.log(globalVar); // 可以在全局范围外访问全局变量
  2. 函数作用域

    在函数作用域中声明的变量只能在函数内部访问。

    1
    2
    3
    4
    5
    6
    7
    function functionScopeExample() {
    var localVar = "I'm local"; // 函数作用域内的变量
    console.log(localVar); // 可以在函数内部访问局部变量
    }

    functionScopeExample();
    console.log(localVar); // 会引发错误,局部变量在函数外不可见
  3. 块级作用域

    使用letconst可以创建块级作用域。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    function blockScopeExample() {
    if (true) {
    let blockVar = "I'm in a block"; // 块级作用域内的变量
    console.log(blockVar); // 可以在块内部访问块级变量
    }
    console.log(blockVar); // 会引发错误,块级变量在块外不可见
    }

    blockScopeExample();
  4. 闭包作用域

    闭包允许内部函数访问外部函数的作用域。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function outerFunction() {
    var outerVar = "I'm outer";

    function innerFunction() {
    console.log(outerVar); // 内部函数可以访问外部函数的作用域
    }

    return innerFunction;
    }

    var closure = outerFunction();
    closure(); // 调用闭包函数,它仍然可以访问outerVar
  5. 模块作用域

    在模块中,变量和函数默认是私有的,除非明确导出。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // module.js
    var moduleVar = "I'm in a module"; // 模块作用域内的变量

    function moduleFunction() {
    console.log(moduleVar); // 可以在模块内部访问模块变量
    }

    export { moduleVar, moduleFunction };

    // main.js
    import { moduleVar, moduleFunction } from './module.js';

    console.log(moduleVar); // 可以在主程序中访问导出的模块变量
    moduleFunction(); // 可以在主程序中调用导出的模块函数

对于作用域链的个人理解

​ 作用域链遵循就近原则(也称为词法作用域),这意味着在查找变量或函数时,JavaScript引擎首先在当前作用域内查找,如果找到匹配的变量或函数,就会停止搜索并使用该变量或函数。只有当在当前作用域找不到时,JavaScript引擎才会沿着作用域链向外层作用域查找,直到找到匹配的变量或函数,或者达到全局作用域为止。