javascript - 了解有关闭包的匿名 JavaScript 函数定义

标签 javascript closures anonymous-function

我从概念上很好地理解了闭包,但是出现了一个我不太理解的问题。

当创建一个函数以将某些值传递给内部函数而不在返回时将其绑定(bind)到最外层函数的最终值时,这似乎是不允许的:

function buildList(list) {
    var result = [];
    for (var i = 0; i < list.length; i++) {
            function (x) {  // this anonymous function definition...
                var item = 'item' + list[x];
                result.push(
                    return function () {
                        console.log(item + ' ' + list[x]);
                    };
                );
            }(i);           // and simultaneous invocation...
    }
    return result;
}

如果我将闭包完全移到 .push() 的调用中,一切都会正常:

function buildList(list) {
    var result = [];
    for (var i = 0; i < list.length; i++) {
            result.push(
                function (x) {  // wrapper now inside the call to .push()
                    var item = 'item' + list[x];
                    return function () {
                        console.log(item + ' ' + list[x]);
                    };
                }(i)           // and called here...
            );
    }
    return result;
}

我想知道的是:当我定义将闭包立即包装在 for 循环内部而不是在 .push() 调用内部的匿名函数时,我违反了什么规则?

最佳答案

通过“不允许”,我假设解释器正在提示语法错误。第一种情况你有什么:

result.push(
    return function () {
        console.log(item + ' ' + list[x]);
    };
);

语法上无效。

但即使你删除了返回:

function buildList(list) {
    var result = [];
    for (var i = 0; i < list.length; i++) {
            function (x) {  // this anonymous function definition...
                var item = 'item' + list[x];
                result.push(
                    function () {
                        console.log(item + ' ' + list[x]);
                    }
                );
            }(i);           // and simultaneous invocation...
    }
}

您仍然会收到错误消息。这是因为您没有为 IIFE 指定括号,这意味着 function (x) { ... }() 被视为声明/语句,无论尾随 () 是什么。但是如果你声明一个函数,你需要指定一个名字,这就是为什么 function 之后的 ( 是意外的。如果你想把它当作一个表达式,你必须将其包装在 (...) 中,因此使用 (function (x) { ... })()

在第二种情况下,result.push(...) 的参数只能是一个表达式,因此对于 function (x) { .. . }() 需要被解释;它永远不可能是声明,因此它必须是表达式(函数文字或 IIFE)。

打个比方,将 function() { ... } 想象为字符串 "hello"。你永远不能孤立地使用“hello”;以下代码在语法上无效:

var x = "foo";
"hello";

这本质上就是您对匿名函数所做的事情:

var x = "foo";
function () {
}

应该用这个函数做什么?它没有分配给任何东西,就像前面示例中的 "hello" 没有分配给任何东西一样。但我们知道函数可以被调用,所以我们用 (function() { ... } ()) 所做的就是说“获取我在这里定义的这个函数,然后立即调用它”。它类似于在字符串文字上调用方法:

"abcd".substring(0, 2); // returns "ab"

事实上,您可以使用函数执行类似的操作,我认为这更好地演示了 IIFE 发生的情况:

// logs "hello"
(function() { 
    console.log("hello");
}).call();

括号是消除歧义并告诉解释器您希望将函数视为表达式/文字而不是声明的一种方法。在上面的示例中,如果删除了周围的括号,您将收到有关意外 (.

的相同语法错误

关于javascript - 了解有关闭包的匿名 JavaScript 函数定义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36509428/

相关文章:

c# - 卡住闭包的优雅方式

php - 有没有办法测试闭包是否也是生成器?

javascript - 在 jQuery 中执行此过程的最有效方法是什么?

PHP 匿名函数作为默认参数?

javascript - Highcharts:一次更新多个系列,以获得更流畅的动画

javascript - 如何在 JavaScript 对象数组中查找重复值,并只输出唯一值?

javascript - 从 Backbone.js 中的项目列表渲染项目

function - rust -将用户提供的安全功能包装到不安全的FFI功能中以进行FFI回调

Javascript 沙盒单元测试

javascript - 当从异步函数返回 Promise 时会发生什么?