Friday 7 December 2018

What is wrong with my javascript scope?




The following alerts 2 every time.



function timer() {
for (var i = 0; i < 3; ++i) {
var j = i;
setTimeout(function () {
alert(j);
}, 1000);
}
}

timer();


Shouldn't var j = i; set the j into the individual scope of the setTimeout?



Whereas if I do this:



function timer() {
for (var i = 0; i < 3; ++i) {
(function (j) {
setTimeout(function () {
alert(j);
}, 1000);
})(i);
}
}

timer();


It alerts 0, 1, 2 like it should.



Is there something I am missing?


Answer



Javascript has function scope. This means that



for(...) {
var j = i;
}


is equivalent to



var j;
for(...) {
j = i;
}


In fact, this is how Javascript compilers will actually treat this code. And, of course, this causes your little "trick" to fail, because j will be incremented before the function in setTimeout gets called, i.e. j now doesn't really do anything different than i, it's just an alias with the same scope.



If Javascript were to have block scope, your trick would work, because j would be a new variable within every iteration.



What you need to do is create a new scope:



for(var i = ...) {
(function (j) {
// you can safely use j here now
setTimeout(...);
})(i);
}

No comments:

Post a Comment

php - file_get_contents shows unexpected output while reading a file

I want to output an inline jpg image as a base64 encoded string, however when I do this : $contents = file_get_contents($filename); print &q...