Search code examples
javascriptdom-events

var a = function() vs function a() for event listener?


I'm trying to understand the difference when adding a function to an event listener and what implications it has.

var buttons = document.getElementsByTagName('button');
for (i = 0, len = 3; i < len; i++) {
    var log = function(e) {
        console.log(i);
    }
    buttons[0].addEventListener("click", log);
}

for (i = 0, len = 3; i < len; i++) {
    function log(e) {
        console.log(i);
    }
    buttons[1].addEventListener("click", log);
}

http://jsfiddle.net/paptd/

The first button fires the console.log 3 times while the second only fires it once.

Why and what should you use when adding a function to an event listener in a normal situation?


Solution

  • Well, couple of notes:

    • The first one creates a new log function in each iteration, so every time you add another event listener it adds a new function.
    • The second one creates a global(read about hoisting) log function, If multiple identical EventListeners are registered on the same EventTarget with the same parameters, the duplicate instances are discarded. They do not cause the EventListener to be called twice.

    Specs:

    Invoking addEventListener (or removeEventListener) repeatedly on the same EventTarget with the same values for the parameters type, listener, and useCapture has no effect. Doing so does not cause the event listener to be registered more than once and does not cause a change in the triggering order.

    source thanks to Rob W.

    so the second and third iterations do nothing.

    • You also have a problem of closure, the last iteration sets i to 3 and this is what shown in the console.

    Fixed version with closure:

    var buttons = document.getElementsByTagName('button');
    for (i = 0, len = 3; i < len; i++) {
        var log = (function closure(number) {
            return function () {
                console.log(number);
            }
        })(i);
    
        buttons[0].addEventListener("click", log);
    }
    

    DEMO