我看到在您提供的示例中使用闭包和 IIFE 的唯一原因是教学:展示如何使用 IIFE 交换代码并获得完全相同的结果。此外,它还展示了内部函数如何仍然可以访问外部变量。
正如 Quentin 所说,在这个例子中,没有其他合乎逻辑的理由使用闭包和 IIFE。它甚至会适得其反(降低性能并混淆代码)。
通过“定义”,以后不会调用 IIFE(“立即调用”)。它的主要(也可能是唯一的)用途是提供函数作用域/闭包(就好像它是提供块作用域的其他语言中的“块”一样),同时仍然避免必须使用正常的函数声明,您必须在其中选择一个标识符,它可能与在其他地方定义的另一个标识符发生冲突。
// Normal function declaration:
function someIdentifier() {}
// Let's immediately call it to execute the code.
someIdentifier();
// what happens if "someIdentifier" was defined somewhere else?
// For example in a previous loop iteration?
这就是作者必须在其 for 循环中使用 IIFE 的原因。
在作用域/闭包内,您可以使用所需的任何标识符(用于变量和函数声明),同时防止与作用域外的标识符发生任何冲突。无论是使用函数声明、函数表达式还是 IIFE。
// Using an Immediately Invoked Function Expression:
(function idForRecursion() { // being a Function Expression rather than a declaration, you can even use an identifier here to be used for recursion, and it will not pollute the global scope.
var anyIdentifier;
// If "anyIdentifier" were defined outside, this local definition will "shadow" it for the current closure only, without affecting / polluting the outside definition and value.
// As in normal closures, you can still access variables outside the IIFE.
alert(myGlobalVar);
})();
因此,关于闭包的一个更具教学意义的示例可能是一个 IIFE,其中 uniqueID 在内部并递增但在全局范围内隐藏(通过闭包),因此没有人可以摆弄/干扰它:
var iDCreator = (function () {
var uniqueID = 100; // initial value.
return function innerFn(listOfItems) {
for (var i = 0; i < listOfItems.length; i += 1) {
listOfItems[i]["id"] = uniqueID;
uniqueID += 1;
}
return listOfItems;
};
})(); // "iDCreator" is now a reference to the "innerFn" which has a closure with "uniqueID", but the latter is not accessible from global scope.
// Calling "iDCreator" several times gives truly unique id's, incremented from the previous call.