1

Variables passed to closure by reference. This code:

var figs = ['circle', 'square'];
for (var i in figs) {
    var fig = figs[i];
    document.getElementById(fig).addEventListener("click", function(e) {
        console.log(fig);
    }, false);
}

always log last array element even you click to circle (square, last value of fig variable).

In order to bind actual value of fig variable I use wrapping in function call (so intermediate closure hold loop value):

var figs = ['circle', 'square'];
for (var i in figs) {
    var fig = figs[i];
    document.getElementById(fig).addEventListener("click", (function(fig) {
        return function(e) {
            console.log(fig);
        }
    })(fig), false);
}

Is that possible to avoid wrapping-function in order to pass by value?

UPDATE related questions and answers:

Community
  • 1
  • 1
gavenkoa
  • 45,285
  • 19
  • 251
  • 303
  • 2
    This is not an issue of how values are passed to functions. JavaScript is **always** pass-by-value. The issue here is the *scope* of variables, and specifically that new scopes are only created by function calls. – Pointy Nov 11 '13 at 15:23

2 Answers2

4

No, it is not possible.

However, you can make your code a bit nicer, by taking the code that produces the inner function out of the loop:

var figs = ['circle', 'square'];
function createFigHandler(fig) {
    return function(e) {
        console.log(fig);
    }
}

for (var i = 0; i < figs.length; i++) {
    var fig = figs[i];
    document.getElementById(fig).addEventListener("click", createFigHandler(fig), false);
}

jsFiddle

lonesomeday
  • 233,373
  • 50
  • 316
  • 318
2

You can also use bind and pass an object that encapsulates the variables you need. Then you can make use of this.fig inside the handler to reference your figure.

document.getElementById(fig).addEventListener("click", (function(e) {
     console.log(this.fig);
}).bind({ fig: fig }), false);

You can also bind a primitive value directly, however it will be wrapped in it's respective object wrapper e.g. Number for a number, String for a string, etc.

document.getElementById(fig).addEventListener("click", (function(e) {
    //this will be the same as new String(fig)
}).bind(fig), false);
plalx
  • 42,889
  • 6
  • 74
  • 90
  • Great technique! Especially for in-lining anonymous functions. It save one level of code indent! +1 – gavenkoa Nov 11 '13 at 15:46