JavaScript自执行匿名函数有哪些好的使用场景?

3

我知道什么是自执行匿名函数,但我不清楚何时使用以及为什么要使用。这可能是因为我经常使用jQuery。请提供一些好的使用案例。


1
在循环中使用循环索引作为自由变量的匿名函数 - zerkms
例如,请参见neurosnap在https://dev59.com/v3RB5IYBdhLWcg3wAjNH中的答案。 - Barmar
2个回答

10

基本上,一个自执行的匿名函数(更准确地说是即时调用函数表达式或IIFE)与声明一个命名函数然后立即调用它相同。与命名函数的唯一区别在于IIFE没有名称,因此只能在原地执行(不能从其他地方调用),因此不会向当前命名空间添加名称。

因此,您可以在任何需要将大量代码放在函数内并且该代码仅需要在当前定义的上下文中调用时使用。

以下是一些常见的使用场景:

  1. 在涉及一些本地变量和一些异步操作(ajax、timeout等)的任何类型的循环中,在异步完成函数中希望为每个循环迭代单独访问这些本地变量。

  2. 封装某些顶级代码,其具有自己的作用域和私有且与全局命名空间分离的本地变量,仅运行一次。

  3. 出于任何原因创建一个未命名的函数范围。

示例:

循环索引(针对每个setTimeout()调用单独冻结循环索引):

for (var i = 0; i < max; i++) {
    // capture the loop index into in a closure
    (function(index) {
        setTimeout(function() {
            console.log(index);
        }, 2000);
    })(i);
}

顶级代码封装(创建私有但持久的变量,不在全局范围内):

(function() {
    var cntr = 0;
    window.getUniqueId = function() {
        return ++cntr;
    };
})();
在代码中创建本地可用的缩写变量,否则这些变量将处于顶层作用域。
function Dictionary(initialData) {
    // call parent constructor
    Set.apply(this, arguments);
}

(function() {
    // inherit from Set
    var proto = Dictionary.prototype = new Set();
    var base = Set.prototype;
    // Set constructor back to us
    proto.constructor = Dictionary;

    // override of the base class .add()
    // add(key, value)
    // add(Dictionary)
    // add({key1: value1, key2: value2})
    proto.add = function(arg1, arg2) {
        if (arg1 instanceof Set) {
            // call base class to just add another Set
            base.add.call(this, arg1);
        } else if (typeof arg1 === "object") {
            // cycle through the object and add all properties/values to the Set
            for (var prop in arg1) {
                if (arg1.hasOwnProperty(prop)) {
                    this._add(prop, arg1[prop]);
                }
            }
        } else if (typeof arg2 !== "undefined") {
            // must be add(key, value)
            this._add(arg1, arg2);
        }
        return this;
    }

    proto.get = function(key) {
        return this.data[key];
    }

    // See rest of code here: https://github.com/jfriend00/Javascript-Set/blob/master/dictionary.js

})();

实际上,在这里使用异步操作只会让 OP 感到困惑。您可以将同步回调传递给 mapfilter,也会出现相同的情况。 - zerkms
2
@zerkms - 如果所有操作都是同步的,那么没有必要捕获循环索引,因为在同步回调中循环索引将是有效的。 - jfriend00

0

你所指的是IIFE

它有几种常见的用法:

  1. 它是自包含的,IIFE 中声明的任何变量都不会污染全局空间。例如: (function() { var foo = 123; $(".pop-up-trigger").click(function() { // ... }); }());
  2. 在 JavaScript 中创建“私有变量”。通过声明一些本地变量,然后返回一些函数,这些函数可以访问这些本地变量(分配它们或获取值)。在 IIFE 外部,没有代码可以触及这些本地变量,因此它们是私有的。

  3. 创建作用域。JavaScript 没有块级作用域,只有函数作用域,因此通过拥有一个函数并调用它,就会创建一个新的作用域。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接