JavaScript 封装在函数中的事件监听器

JavaScript Event Listener encapsulated in a function

我有一个函数中的事件侦听器。侦听器和发射器都在同一个函数中。

事件触发时,变量会递增。到目前为止,一切都很好。但是当我多次调用该函数时,在同一个函数调用中多次触发监听器。

var test = function() {    
    var completeStatus = 0;

    $(document).on('gt', function() {
        console.log(++completeStatus);
    });
    $(document).trigger('gt');
}

test();
test();
test();

函数被调用了3次,期望输出3次1。但它输出: 0 1个 0 2个 1

这是为什么以及如何获得所需的行为?

这里有一个 jsfiddle 来试试看。

.on() 添加事件列表,它不会替换以前的:

Attach an event handler function for one or more events to the selected elements.

当一个元素有多个事件监听器时,顺序是明确的:

Event handlers bound to an element are called in the same order that they were bound.

并且.trigger()按顺序执行它们:

Execute all handlers and behaviors attached to the matched elements for the given event type.

因此,

  1. 第一次调用 test 时,您使用 completeStatus = 0 添加事件侦听器并触发它。所以你得到

    0
    
  2. 第二次调用test,之前的事件监听器有completeStatus = 1。然后使用 completeStatus = 0 添加第二个事件侦听器,然后触发这两个事件。所以你得到

    1 // From the first event listener
    0 // From the second event listener
    
  3. 第三次调用test,第一个事件侦听器有completeStatus = 2,第二个有completeStatus = 1。然后您使用 completeStatus = 0 添加第三个事件侦听器,并触发它们。所以你得到

    2 // From the first event listener
    1 // From the second event listener
    0 // From the third event listener
    

因为你正在使用 $(document).trigger('gt');所以它在所有文档事件中启动触发事件,这就是为什么增加函数返回输出的调用

0       //from first function call
1 0     //from second function call 
2 1 0   //frm third function call
.... and so on

解决方案:

var test = function() {    
    var completeStatus = 0;
    var pageInitialized = false;    
    $(document).on('gt', function() {
        if(pageInitialized) return;
        console.log(++completeStatus);
        pageInitialized = true;
    });
    $(document).trigger('gt');
}

test();
test();
test();

如上回复所述.on()添加了事件监听器,所以在你的例子中添加了3次。

除了前面的回答之外,最好避免添加多个侦听器,因为如果您未能删除它们,可能会导致内存泄漏。所以你可以尝试这个解决方案,它在再次添加之前删除事件监听器。

var test = function() {    
   var completeStatus = 0;
   var GT_EVT = 'gt';

   $(document).off(GT_EVT).on(GT_EVT, function() {
      console.log(++completeStatus);
   });

   $(document).trigger(GT_EVT);

}

另一种方法是在每次执行函数时生成唯一的事件和处理程序:

var test = function() {    
    var completeStatus = 0;
    var uniqid = Math.random().toString(36).slice(-8);

    $(document).on('gt' + uniqid, function() {
        console.log(++completeStatus);
    });
    $(document).trigger('gt' + uniqid);
}

test();
test();
test();

Fiddle

但是对性能的影响呢?有没有advantage/disadvantage使用这种方法的?