事件监听器是否需要在 IIFE 中?

Do event listeners need to be inside IIFE?

我经常看到很多事件监听器代码都封装在IIFE里面(function(e){}())我觉得没有必要把事件监听器放在IIFE里面。例如:

没有 IIFE

jQuery(window).on("load", function(){
    console.log("inside plain load");
});

有 IIFE

(function(){
    jQuery(window).on("load", function(){
        console.log("inside wrapped load");
    });
}())

如果我们将以上代码一起包含在一个 js 文件中,则在加载事件时它们仅根据编写的顺序执行。

我知道 IIFE 会调用自身,但是在其中设置事件侦听器有什么用?无论如何它只会在事件发生时触发。

对于你的例子来说没有区别。

使用 IIFE 的主要原因是防止在全局范围内泄漏变量。

(function(){
    let notLeakedVariable = 'something'
    jQuery(window).on("load", function(){
        console.log("inside wrapped load");
        console.log(notLeakedVariable)
    });
}())

如果没有 IIFE,您将在全局范围内泄漏变量。

通过包装您的侦听器,您甚至可以将多个侦听器分组,它们将通过闭包共享相同的作用域。

(function(){
    let sharedVariable = 'something'
    jQuery(window).on("load", function(){
        console.log("inside wrapped load");
        // sharedVariable is accessible 
    });

    jQuery(selector).on("click", function(){
        // sharedVariable is accessible 
    });
}())

它不会影响回调的绑定方式,但您可能会看到它有几个原因。

  1. 如果JS文件直接通过标签加载,那么IIFE会关闭在IIFE中创建的任何变量,它们在全局window对象上是不可见的。例如,如果您在 IIFE 中写了 var x = 'foo',它不会显示为 window.x,但如果没有 IIFE,它就会显示为
  2. 某些函数 return 您不想公开的值。例如 jQuery(window).on(...) 实际上是 return 的东西。由于 IIFE,您不能简单地在它前面分配一个变量并获取它。

您使用 IIFE 是因为您希望本地作用域将所有内容与全局作用域隔离。

(function() {
  var count = 0;
  
  document.body.addEventListener('click', function() {
    console.log("hi", count++);
  });
}());
hello world

上面的代码,世界上没有其他人可以触摸count。只有执行 console.log 的函数才能访问它。所以count不污染全局范围,也不受外界影响。

请注意,IIFE 提供的是局部作用域。某些 JavaScript 专家可能将其称为闭包,但闭包在这里与它无关。您在这里只需要一个本地范围。

执行 console.log 的函数是一个闭包。它是一个采用作用域链并能够访问 count 的函数。这是闭包的行为。

因此此函数可以访问 count,而其他任何函数都不能。所以这个IIFE提供了一个很好的方式来写一些自包含的东西,不污染外界,也不让外界污染它。