gpt4 book ai didi

JavaScript 闭包与匿名函数

转载 作者:IT老高 更新时间:2023-10-28 11:14:20 32 4
gpt4 key购买 nike

我和我的一个 friend 目前正在讨论什么是 JS 中的闭包,什么不是。我们只是想确保我们真的正确理解它。

让我们以这个例子为例。我们有一个计数循环,并希望在控制台上延迟打印计数器变量。因此我们使用 setTimeout闭包捕获计数器变量的值以确保它不会打印值 N 的 N 倍。

没有的错误解决方案闭包或任何靠近 的东西闭包将会:

for(var i = 0; i < 10; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}

这当然会打印 i 值的 10 倍在循环之后,即 10。

所以他的尝试是:
for(var i = 0; i < 10; i++) {
(function(){
var i2 = i;
setTimeout(function(){
console.log(i2);
}, 1000)
})();
}

按预期打印 0 到 9。

我告诉他他没有使用 关闭捕获 i ,但他坚持认为他是。我证明他不使用 闭包通过将 for 循环体放在另一个 setTimeout 中(将他的匿名函数传递给 setTimeout ),再次打印 10 次 10。如果我将他的函数存储在 var 中,同样适用并在循环后执行它,同时打印 10 次 10。所以我的论点是 他并没有真正捕获 i 的值(value) ,使他的版本不是闭包。

我的尝试是:
for(var i = 0; i < 10; i++) {
setTimeout((function(i2){
return function() {
console.log(i2);
}
})(i), 1000);
}

所以我捕获 i (在闭包中命名为 i2),但现在我返回另一个函数并传递它。 就我而言,传递给 setTimeout 的函数确实捕获了 i .

现在谁在使用闭包,谁没有?

请注意,两个解决方案都在延迟的控制台上打印 0 到 9,因此它们解决了原始问题,但我们想了解这两个解决方案中的哪一个 使用闭包 来实现这一点。

最佳答案

编者注: JavaScript 中的所有函数都是闭包,如本 post 中所述。然而,我们只对识别这些函数的一个子集感兴趣,这些函数从理论的 Angular 来看是 interesting。此后,除非另有说明,否则对闭包一词的任何引用都将指代该函数子集。

闭包的简单解释:

  • 取一个函数。我们称之为 F。
  • 列出F的所有变量。
  • 变量可能有两种类型:
  • 局部变量(绑定(bind)变量)
  • 非局部变量(自由变量)
  • 如果 F 没有自由变量,那么它不能是闭包。
  • 如果 F 有任何自由变量(在 F 的 a 父作用域中定义),则:
  • 必须只有一个 F 的父作用域与 自由变量绑定(bind)。
  • 如果 F 是 从外部 引用 那个 父作用域,那么它变成了 2 的闭包 2 自由 _67910404
  • 自由变量称为闭包 F 的上值。

  • 现在让我们用它来找出谁使用闭包,谁不使用(为了便于解释,我已经命名了函数):

    案例 1:你 friend 的程序
    for (var i = 0; i < 10; i++) {
    (function f() {
    var i2 = i;
    setTimeout(function g() {
    console.log(i2);
    }, 1000);
    })();
    }

    在上面的程序中有两个函数: fg 。让我们看看它们是否是闭包:

    对于 f :
  • 列出变量:
  • i2 本地 变量。
  • i 是一个 免费 变量。
  • setTimeout 是一个 免费 变量。
  • g 本地 变量。
  • console 是一个 免费 变量。
  • 找到每个自由变量绑定(bind)的父作用域:
  • i 绑定(bind)到全局范围。
  • setTimeout 绑定(bind)到全局范围。
  • console 绑定(bind)到全局范围。
  • 引用的函数 在哪个范围内? 全局范围
  • 因此 i 不是 通过 f 上关闭。
  • 因此 setTimeout 不是 f 上关闭。
  • 因此 console 不是 f 上关闭。

  • 因此函数 f 不是闭包。

    对于 g :
  • 列出变量:
  • console 是一个 免费 变量。
  • i2 是一个 免费 变量。
  • 找到每个自由变量绑定(bind)的父作用域:
  • console 绑定(bind)到全局范围。
  • i2 绑定(bind)到 f 的范围。
  • 引用的函数 在哪个范围内? setTimeout 范围。
  • 因此 console 不是 g 上关闭。
  • 因此 i2g 关闭超过

  • 因此,函数 g 是自由变量 i2(它是 g 的上值) 的闭包,当 引用 中的


    对你不利:你的 friend 正在使用闭包。内部函数是一个闭包。

    案例 2:您的程序
    for (var i = 0; i < 10; i++) {
    setTimeout((function f(i2) {
    return function g() {
    console.log(i2);
    };
    })(i), 1000);
    }

    在上面的程序中有两个函数: setTimeoutf 。让我们看看它们是否是闭包:

    对于 g :
  • 列出变量:
  • f 本地 变量。
  • i2 本地 变量。
  • g 是一个 免费 变量。
  • 找到每个自由变量绑定(bind)的父作用域:
  • console 绑定(bind)到全局范围。
  • 引用的函数 在哪个范围内? 全局范围
  • 因此 console 不是 console 上关闭。

  • 因此函数 f 不是闭包。

    对于 f :
  • 列出变量:
  • g 是一个 免费 变量。
  • console 是一个 免费 变量。
  • 找到每个自由变量绑定(bind)的父作用域:
  • i2 绑定(bind)到全局范围。
  • console 绑定(bind)到 i2 的范围。
  • 引用的函数 在哪个范围内? f 范围。
  • 因此 setTimeout 不是 console 上关闭。
  • 因此 gi2 关闭超过

  • 因此,函数 g 是自由变量 g(它是 i2 的上值) 的闭包,当 引用 中的


    对你有好处:你正在使用闭包。内部函数是一个闭包。

    所以你和你的 friend 都在使用闭包。别吵了我希望我清除了闭包的概念以及如何为你们俩识别它们。

    编辑: 关于为什么所有函数都是闭包的简单解释(学分@Peter):

    首先让我们考虑以下程序(它是 control ):

    lexicalScope();

    function lexicalScope() {
    var message = "This is the control. You should be able to see this message being alerted.";

    regularFunction();

    function regularFunction() {
    alert(eval("message"));
    }
    }


  • 我们知道 gsetTimeout 都不是上述定义 中的闭包
  • 当我们执行程序 时,我们期望 lexicalScope 收到警报 因为 regularFunction 不是它的闭包,包括它的父对象 -x704 _04 _04 _6 5 _6 5 6 5 6 5 0 7 0 5 6 5
  • 当我们执行程序 时,我们观察到 message 确实被警告了。

  • 接下来让我们考虑以下程序(它是 alternative ):

    var closureFunction = lexicalScope();

    closureFunction();

    function lexicalScope() {
    var message = "This is the alternative. If you see this message being alerted then in means that every function in JavaScript is a closure.";

    return function closureFunction() {
    alert(eval("message"));
    };
    }


  • 我们知道只有 regularFunction 是一个闭包 从上面的定义
  • 当我们我们预计 message不被惊动因为 message是一个闭合(执行程序即它只能访问其所有非本地变量功能创建(see this answer的时间) - 这不包括 closureFunction )。
  • 当我们执行程序 时,我们观察到 message 实际上正在被警告。

  • 我们从中推断出什么?
  • JavaScript 解释器对待闭包的方式与对待其他函数的方式没有区别。
  • 每个函数都带有它的 scope chain。闭包没有 单独的 引用环境。
  • 闭包就像其他所有函数一样。我们只是在它们被 引用时称为闭包 在范围 之外,它们所属的范围 因为 _09204567 这是一个有趣的案例
  • 关于JavaScript 闭包与匿名函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12930272/

    32 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com