0

我知道这里和其他地方有很多关于自我执行功能的帖子,但在阅读帖子后我仍然有一些问题。

  1. 为什么我会为变量分配一个自执行函数?如果似乎他们无论如何都会执行自己。

    var myFunc=(function() {
     console.log('Hello World');
    })();
    
  2. 我读了很多,使用自执行函数的原因是保持变量私有。如果我有一个非自动执行的函数,那么我在该函数中定义的所有内容无论如何都会是私有的?!

    (function() {
     var name="my Name"
     console.log(name);
    })();
    
    vs.
    
     function() {
     var name="my Name"
     console.log(name);
     };
     //its the same
    

所以我不太明白自执行函数是如何保持本地范围的(因为你可以使用非自执行函数来做到这一点)所以我看到的唯一原因是当你想自动执行时使用它们,例如在页面加载时。

谢谢!

还有一个问题:

var test=(function myFunc(){
      var name="Hello World"
      return {
        test1: function(){
          return name;
        },
        test2:function(){
          return name+"1"
        }
      }
    })()

    test.test1()

vs

    var test=function myFunc(){
      var name="Hello World"
      return {
        test1: function(){
          return name;
        },
        test2:function(){
          return name+"1"
        }
      }
    }

    test.test1()

--> 这里到底发生了什么,因为 IIFE 我可以实际执行 test.test1() 而不是使用常规函数?

4

8 回答 8

1
  1. 如果那个 IIFE 没有返回任何东西,那么将它分配给任何东西确实是没有用的。虽然当然可能有 IIFE 会返回您以后想要使用的东西的例子;在这种情况下,IIFE 是设置某些对象的私有范围,例如:

    var foo = (function () {
        var bar = 'something';
        // here be dragons
        return baz;
    })();
    

    这为您提供了一个私有范围来组装baz,而无需将临时变量泄漏到全局范围中。

  2. 这些示例没有区别,除了第二个不执行,因此从不做任何事情。范围界定和范围界定的目的没有改变。

于 2017-09-21T09:13:08.010 回答
1

当你想保持你的范围被包含时,你通常将你的函数包装在一个匿名函数中。这也是仍然很流行的模块模式的一部分:

https://toddmotto.com/mastering-the-module-pattern/

然后,您可以将该IIFE的结果分配给一个变量,这样您的范围只能通过调用该变量来访问。

myScope.myLocallyScopedProperty or myScope[myLocallyScopedProperty]

您的其他功能需要手动调用,它也可以从任何地方访问。

我建议阅读 Todd Moto 的文章,它解释了很多。

于 2017-09-21T09:13:20.860 回答
1

首先,简而言之,这些不是自动执行的功能。(这将是一个递归函数。)这些是内联调用函数表达式(IIFE)。函数不调用自身,表达式调用函数。

为什么我会为变量分配一个自执行函数?

那不是该代码的作用。它将调用 IIFE的结果分配给变量。当你想要这个结果时,你会使用它,例如:

var x = (function() {
    var n = 0;
    return {
        increment: function() { return ++n; }
    };
})();
console.log(typeof x); // "object"
console.log(x.increment()); // 1
console.log(x.increment()); // 2

x不接收 IIFE,它接收 IIFE返回的内容 ——在这种情况下,是一个带有函数的对象。

我读了很多,使用自执行函数的原因是保持变量私有。如果我有一个非自动执行的函数,那么我在该函数中定义的所有内容无论如何都会是私有的?!

是的,这是真的。当您只需要执行一次 IIFE 中的操作时,您可以使用IIFE。否则,绝对是你定义函数,给它一个名字,然后在你需要的地方重用它。函数内部的变量确实是它私有的(除非以某种方式公开),并且特定于对函数的每次调用。

于 2017-09-21T09:13:38.390 回答
1

以 IIFE(或立即调用的函数表达式)的形式,它们可以用于创建插件用作命名空间并附加到 window / jquery / 或其他全局级别对象以供以后使用。


当您命名一个函数(例如将匿名函数分配给变量)时,您可以稍后通过使用括号调用变量来使用它,在您的示例中,定义 myFunc 为

var myFunc=(function() {
 console.log('Hello World');
}); 

稍后在代码中将其用作myFunc();

在您的示例中,您通过立即调用将函数的输出直接存储在变量中,并且没有要存储的输出。

所以,如果你以后写console.log(myFunc);,就会有undefined输出。


您的代码示例中更好的 IIFE 示例是下面提到的示例。

(function() {
 var name="my Name"
 console.log(name);
})();

它执行,执行console.log,就是这样。在您的情况下,不会向命名空间或全局对象添加任何内容。


您的最后一个示例定义了一个函数,然后不执行它,并且由于它没有分配命名变量或名称,因此它给出了语法错误,以后不能在代码中使用。所以,下面的例子是没用的。

function() {
 var name="my Name"
 console.log(name);
 };

您使用var test=添加了另外两个示例function myFunc。第一个将与test.test1(). 对于第二个,您需要先将 test 作为函数进行评估,然后调用它的函数,例如test().test1().

于 2017-09-21T09:14:02.363 回答
1

1:将 IIFE 分配给局部变量对于这样的事情是有意义的:

var getID = (function () {
  var id = 0;
  return function () { return id++; };
})();

通过这种方式,您可以获得新的 ID,而无需冒险从代码中的其他任何地方重置内部计数器,除非重新声明变量。

2:基本上你通过创建一个函数来创建范围。但是,如果您不执行它,那么它不会做任何事情。所以如果你有这个:

function () { return 'foo' };

如果它没有分配给变量或没有名称,你想如何调用它?它本身不会做任何事情,因为它没有被调用。类似的东西是死代码,可以安全地删除。

于 2017-09-21T09:16:06.610 回答
1

你的第一件事毫无意义:

var myFunc = =(function() {
       console.log('Hello World');
    })();

myFunc不是一个函数,它是undefined

在我看来,自执行函数的意义在于打包一些必须立即执行的代码。

var p1=1, p2=2, obj = {
   prop: (function(x,y){ return x+y;})(p1, p2)
}

或者 避免覆盖已经定义的函数/对象,以防您的脚本将被插入到已经存在的应用程序中,并且如果您愿意,还可以创建一种私有方法:

function aFunction() {
  console.log('a code');
}
(function(w) {
  function aFunction() {
    console.log('b code');
  }
  w.run = function() {
    aFunction();
  };
})(window)
aFunction();
run();

于 2017-09-21T09:22:18.113 回答
1

您使用自执行函数仅在范围之外公开您需要的内容。我想我有一个比较清楚的例子:

let myObject = (function(){
  let privateVariable = "I'm private";
  function privateMethod() {
    //private method
  };
  function methodToExpose() {
    //this method I will expose
  }

  //what is returned here, is what is public
  return {
    PublicMethod: methodToExpose
    //other public properties
  }
}());

因此,该函数立即执行,发生的情况是我有一个对象,该对象由我从函数返回的内容定义。

我可以给你的另一个例子是在闭包中保留当前范围的变量,但你不会真正使用它,因为我们现在有let. 一个实际的例子:

<span id="1">old</span>
<span id="2">old</span>
<span id="3">old</span>
<span id="4">old</span>
<script>
var toPrint = "";
for (var i = 1; i <= 4; i++) {
  toPrint = "new: " + i;
  document.getElementById(i.toString()).addEventListener('click', function(event){ event.target.innerHTML = toPrint; })
}

</script>

当您单击跨度时,该值将替换为值...“new:4”!那是因为当你完成执行时,这就是 toPrint 的值。分配给 click 事件的函数检索该 toPrint,并且在检索它时,它是“new: 4”。我们用闭包解决这个问题:

<span id="1">old</span>
<span id="2">old</span>
<span id="3">old</span>
<span id="4">old</span>
<script>
var toPrint = "";
for (var i = 1; i <= 4; i++) {
  toPrint = "new: " + i;
  document.getElementById(i.toString()).addEventListener('click', function(event){ 
    var currPrint = toPrint;
    return function(event){ event.target.innerHTML = currPrint ; };
  }())
}

</script>

通过使用自执行函数,我们将 toPrint 的当前值保存在本地范围内的 currPrint 变量中。当我们稍后单击一个跨度时,分配给单击的函数甚至将使用变量 currPrint,其中包含 toPrint 在分配函数时的值,而不是 toPrint 在完成执行时的值。

请注意,这也可以通过使用 let 而不是 var 来解决,但它仍然是自执行函数的示例 :)

于 2017-09-21T09:31:04.280 回答
0

我猜你在这里错过了一些东西。只是为了让基本的事情清楚 - 如果你将一个自执行的函数分配给一个变量,那么return value此时执行的函数的实际值被分配给变量而不是函数本身。

var myFunc = (function() {
    console.log('Hello World');
})();
myFunc(); // will throw error: TypeError: myFunc is not a function
myFunc === undefined

var myFunc = (function() {
    console.log('Hello World');
    return 'japp';
})();
myFunc(); // will throw error: TypeError: myFunc is not a function
myFunc === 'japp'

那么为什么会出现这种模式呢?

IIFE 非常有用

  • 如果您声明,请限制范围

    var test = 'test'; // var test actually will be assigned as a property of the current context (this)
    window.test = 'test'; // so you pollute the global namespace which is not a good practice
    

    所以这会更好

    (function() {
        var test = 'test';
    })();
    
  • IIF 的另一个非常好的优点是您可以使用“私人”实现设计

    var myFunc;
    (function() {
        var i = 0; // i is available for myFunc with private access
        myFunc = function() { console.log( ++i ) };
    })();
    myFunc(); // logs 1
    myFunc(); // logs 2
    
于 2017-09-21T09:29:24.787 回答