开发者

JavaScript - saving variables inside functions without calling the functions

Can someone help me with a JavaScript riddle?

Consider the following JavaScript code:

var a[];

for (i=0;i<10;i++)
{
    a[i] = function(){alert ("I am " + i);};
}

a[5]();

Now obviously, the last line开发者_Go百科 will cause the alert to read "I am 9", and not "I am 5", since the value of i is 9 at the end of the for loop.

I want the alert to print "what it is supposed to", but without changing the way which I call functions from the array, i.e. - no parameters.

A hint I received: try defining a function which calls another function.

Please help!!! Thank you :-)


The hint you received is a little deceptive. You don't want to define a function that calls another (you'd have the same problem). Rather, you want to define one that returns another.

Example: http://jsfiddle.net/sX92Q/

var a = [];

for (i = 0; i < 10; i++) {
    a[i] = alertFunc(i);
}

   // return a function that closes around the proper value of "i"
function alertFunc(i){
    return function() {
        alert(i);
    };
};

a[5]();

This is effectively the same as those that use an anonymous function in the loop, but it is more efficient since the anonymous function doesn't need to be reconstructed each iteration.

Generally, you don't want to create duplicate functions in a loop.


Side note. In javascript, this:

var a[];

should be:

var a = [];


This works:

var a = [];

for (i=0;i<10;i++)
{
    a[i] = (function(i) {
        return function(){alert ("I am " + i);};
    })(i);
}

a[5]();

In your example, the anonymous function holds a reference to the i variable, however this variable is modified after the function's creation. So at the time you call the function, you see that modified value.

To avoid that, you must make a copy of that variable, which is what the code above does.

Alternatively, in Javascript 1.7 you would use let definitions:

for (i=0;i<10;i++)
{
    let j = i;
    a[i] = function(){alert ("I am " + j);};
}


var a[];

for (i=0;i<10;i++)
{
    a[i] = function(){alert ("I am " + i);};
}

a[i = 5]();

Cheat since (i = 5) === 5

Don't actaully do this

Use one of the real solutions above.

Alternatively:

var a = [];

for (i=0;i<10;i++)
{
    (function(j) {
        a[j] = function() { 
            alert ("I am " + j);
        };
    }(i)) 
}

a[i]();

Use a closure to make j the current value of i


The following code will work:

var a[];

for (i=0;i<10;i++)
{
    a[i] = (function(i) {
        return function(){alert ("I am " + i);};
   })(i);
}

a[5]();

Here i is converted to a local variable.


The reason your first example doesn't work is, the data has to be stored somewhere. You've got ten different values to store, but only one i variable, so it doesn't work.

Other posters suggest using closure, which works, but your question is looking for a way to do it without calling functions. I'd suggest this:

var a = [];
for (i=0; i<10; i++) {
  a[i] = function(i){alert("I am " + i);};
}
a[5](5);

Of course this makes one wonder, why even have ten different functions when they all do the same thing? Why not just:

var whoAmI = function(i){ alert("I am " + i); };
whoAmI(5);

Perhaps you need a function that you can pass around to some external API which calls it with no arguments? In that case do the closure function-that-makes-a-function thing.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜