I'm attempting to create a function that captures a number of elements on the page, iterates through them and applies a mousedown event listener, then calls another function and passes it some data in a variable. This variable changes throughout the course of the loop, so I want to utilize a closure so that when the event is triggered, the variable has the expected value from that iteration instead of simply referencing the value from the last iteration of the loop.
I have been reading other answers on this site (and others) and have found myself at a loss for how to make this work, because no matter how many of these seemingly correct solutions I use, I continue to get the last value from the data.
Here are a number of variations I've tried - Each shows the expected value when it's attached, but shows the incorrect value when triggered. I'd appreciate your help identifying what I'm doing incorrectly here. Thanks!
Nomenclature Used:
_externalFunction() - The external function that I'd like to call when the event is fired, passing into it the data object.
changingDataValue - The original data value that I'd like sent to the external function.
Using a closure within a different function
function addMouseDown(elem, data) {
    elem.addEventListener("mousedown", function () {
        _externalFunction(data);
        console.log("triggered - mouseDown: " + data.value);
    }, false);
    console.log("attached - mouseDown: " + data.value);
}
addMouseDown(elements[i], changingDataValue);
Using a closure within another function, and a closure within the event listener
function addMouseDown(elem, data) {
    (function(d) {
        elem.addEventListener("mousedown", function () {
            (function (e) {
                _externalFunction(e);
                console.log("triggered - mouseDown: " + e.value);
            })(d);
        }, false);
    })(data);
    console.log("attached - mouseDown: " + data.value);
}
addMouseDown(elements[i], changingDataValue);
Using a closure within another function:
function addMouseDown(elem, data) {
    (function(d) {
        elem.addEventListener("mousedown", function () {
            _externalFunction(d);
            console.log("triggered - mouseDown: " + d.value);
        }, false);
    })(data);
    console.log("attached - mouseDown: " + data.value);
}
addMouseDown(elements[i], changingDataValue);
Closure within the script itself
(function (data) {
    elements[i].addEventListener("mousedown", function () {
       _externalFunction(data);
       console.log("triggered - mouseDown: " + data.value);
    }, false);
    console.log("attached - mouseDown: " + data.value);
})(changingDataValue);
Closure within event handler
elements[i].addEventListener('mousedown', (function(data) {
    return function() {
        _externalFunction(data);
        console.log("triggered - mouseDown: " + data.value);
    };
})(changingDataValue), false);
console.log("attached - mouseDown: " + changingDataValue.value);
Works great except that it actually calls the external function before the event has been triggered, but it does pass in the expected value
(function (elem, data) {
    elem.addEventListener("mousedown", (function (d) {
        _externalFunction(d);
        console.log("triggered - mouseDown: " + d.value);
    })(data), false);
    console.log("attached - mouseDown: " + data.value);
})(elements[i], changingDataValue);
Again, I appreciate any help anyone can provide here. Thanks!
                        
In your
elem.addEventListeneryou're passing a self-executing anonymous function. It is essentially sending the returned value instead of a reference to a function.In other words the following gets executed and the value (in this case,
undefined) is then passed as the 2nd argument inelem.addEventListener:If you turn that into a normal function call, your
datavariable will still be in scope when you reference it in the callback (since it is bound to that anonymous function). I'd suggest utilizingcall/applyto keep change thethisscope to the element that was clicked for later development.If I load the code above and then click on link2, then link1 I get the following output: