JavaScript Loop Variable Scope

JavaScript loop variable scope

See the MDN for the "initialization parameters" of a for-loop:

An expression (including assignment expressions) or variable declaration. Typically used to initialize a counter variable. This expression may optionally declare new variables with the var keyword. These variables are not local to the loop, i.e. they are in the same scope the for loop is in. The result of this expression is discarded.

JavaScript: Understanding let scope inside for loop

General Explanation

When you use let in the for loop construct like you show, there is a new variable i created for each invocation of the loop that is scoped just to the block of the loop (not accessible outside the loop).

The first iteration of the loop gets its value from the for loop initializer (i = 1 in your example). The other new i variables that are created each loop iteration get their value from the i for the previous invocation of the loop, not from the i = 1 which is why they aren't all initialized to 1.

So, each time through the loop there is a new variable i that is separate from all the other ones and each new one is initialized with the value of the previous one and then processed by the i++ in the for loop declaration.

For your ES6 code of this:

for(let i = 1; i <= 5; i++) {   setTimeout(function(){       console.log(i);   },100);} 

Javascript for-loop variable scope?

Before ECMAScript 6, javascript only supports function scoping. A variable declared inside a function is visible anywhere inside that function. Even this:

function foo() {  if(true) {    if(true) {      var v = 7;    }  }
console.log(v); // 7}foo();

JS loop variable scope

We can achieve such behavior by creating explicit function scope. But is it the standard way / followed in production?

Yes. Functions are the only possibility to introduce a new scope in JavaScript (though that might change in future versions with let); and IIFEs are heavily used in production as well.

What other things can be done?

To limit the scope of i to the for-loop's block? None (let alone let). However, you hardly will need to do that, since nothing will interfere with it - var i is still scoped local to your function. Sometimes, you even might want to use i after the loop as an ongoing counter.

Variable scope in Javascript for loop

The first example will either add or modify the global variable x, which is generally to be avoided if not the desired outcome.

While your second example works as desired (no side effects) an alternative that looks better in my opinion would be

function bar()
{
for (var x=0; x< 100; x++) {}
}

Context and variable scope in ES6 loops and forEach

Regular functions use execution context to set the value of this, meaning that in in most cases, the value of this is determined by how a function is called, i.e. the value of this is set according to the environment in which the function is executed.

Arrow functions do not have their own this value, instead they use lexical scoping, meaning the value of this inside an arrow function is always inherited from the enclosing scope, i.e. it is set to the this value of the enclosing execution context.

This is explained in the documentation as well

Until arrow functions, every new function defined its own this value
(a new object in case of a constructor, undefined in strict mode
function calls, the context object if the function is called as an
"object method", etc.). This proved to be annoying with an
object-oriented style of programming.

....

Arrow functions capture the this value of the enclosing context

The third example posted is just a regular for loop, and has very little in common with functions, and can't really be compared to the two first code examples.

for loops work the same in ES2015 as they always have, there generally is no special scope in for loops for variables, as variables (defined with var) are function scoped.

However, ES2015 does introduce variables that can are block scoped as wel, and as a for loop is in fact a block (for (what) {block}), those variables can be used, and they are defined with either the let keyword, or the const keyword for a constant (that can not be changed) .

For those that prefer code

var o = {
nums : [1,2,3,4],
fn : function() {
var self = this;
this.nums.forEach(function(v) {
// "this" in this context would be the window,
// but "self" would be the object "o", hence the common use of this hack
});

this.nums.forEach((v) => {
// "this" in this context, would be the object "o"
// that happens because the "this-value" in the fn() function,
// ... is the parent object
// and the arrow function inherits that this-value
});

for (var i=0; i<this.nums.length; i++) {
// "this" in this context is what it has always been,
// a for-loop has the same this-value as the surrounding scope
}
}
}

o.fn(); // called from global context "window"


Related Topics



Leave a reply



Submit