搜索

首页  >  问答  >  正文

JavaScript闭包的工作原理是什么?

<p>如何向一个对JavaScript闭包的概念(例如函数、变量等)有了解,但不理解闭包本身的人解释闭包?</p> <p>我看过维基百科上给出的Scheme示例,但不幸的是没有帮助。</p>
P粉494151941P粉494151941456 天前428

全部回复(2)我来回复

  • P粉734486718

    P粉7344867182023-08-23 09:30:55

    在JavaScript中,每个函数都维护着与其外部词法环境的链接。词法环境是一个作用域内所有名称(例如变量、参数)及其值的映射。

    所以,每当你看到 function 关键字时,该函数内部的代码可以访问在函数外部声明的变量。

    function foo(x) {
      var tmp = 3;
    
      function bar(y) {
        console.log(x + y + (++tmp)); // 将输出 16
      }
    
      bar(10);
    }
    
    foo(2);

    这将输出 16,因为函数 bar 闭包了参数 x 和变量 tmp,它们都存在于外部函数 foo 的词法环境中。

    函数 bar 与其与函数 foo 的词法环境的链接一起,构成了一个闭包。

    函数不需要 返回 来创建一个闭包。仅通过声明,每个函数都会闭包其封闭的词法环境,形成一个闭包。

    function foo(x) {
      var tmp = 3;
    
      return function (y) {
        console.log(x + y + (++tmp)); // 也将输出 16
      }
    }
    
    var bar = foo(2);
    bar(10); // 16
    bar(10); // 17

    上述函数也将输出 16,因为 bar 中的代码仍然可以引用参数 x 和变量 tmp,尽管它们不再直接在作用域内。

    然而,由于 tmp 仍然存在于 bar 的闭包中,它可以被递增。每次调用 bar 时,它都会递增。

    闭包的最简单示例是:

    var a = 10;
    
    function test() {
      console.log(a); // 将输出 10
      console.log(b); // 将输出 6
    }
    var b = 6;
    test();

    当JavaScript函数被调用时,会创建一个新的执行上下文 ec。除了函数参数和目标对象之外,该执行上下文还接收到调用执行上下文的词法环境的链接,这意味着在外部词法环境中声明的变量(在上面的示例中,即 ab)可以从 ec 中访问。

    每个函数都创建了一个闭包,因为每个函数都有与其外部词法环境的链接。

    请注意,闭包中可见的是变量本身,而不是副本。

    回复
    0
  • P粉904405941

    P粉9044059412023-08-23 00:50:56

    闭包是以下内容的配对:

    1. 一个函数和
    2. 对该函数外部作用域(词法环境)的引用

    词法环境是每个执行上下文(堆栈帧)的一部分,它是标识符(即局部变量名)和值之间的映射。

    JavaScript中的每个函数都保持对其外部词法环境的引用。当函数被调用时,此引用用于配置创建的执行上下文。此引用使函数内部的代码能够“看到”在函数外部声明的变量,无论函数何时何地被调用。

    如果一个函数是由另一个函数调用的,那么就会创建一系列对外部词法环境的引用。这个链条被称为作用域链。

    在下面的代码中,inner与调用foo时创建的执行上下文的词法环境形成了闭包,闭包包含变量secret

    function foo() {
      const secret = Math.trunc(Math.random() * 100)
      return function inner() {
        console.log(`The secret number is ${secret}.`)
      }
    }
    const f = foo() // 无法直接从外部访问`secret`
    f() // 检索`secret`的唯一方法是调用`f`

    回复
    0
  • 取消回复