Scoping rules are different for the old var and the ECMAScript 6 let and const. All of them have global scope when declared outside any of the functions and blocks:
/*global scope, visible also outside the file they are declared in.*/
var firstName = "Francesco";
var surName = "Abbruzzese";
function fullName(x, y, spaces){
x + Array(spaces+1).join(' ') + y;
}
However, variables defined with var are visible within the inner function they are defined in, while variables defined with let and const are visible just in the inner block they are defined in:
function scopeTest(x: number) {
if (x > 0) {
var result: number = x;
}
else {
result = -x; //correct result is visible within the whole function
}
return result; //correct result is visible within the whole function
}
function scopeTestLet(x: number) {
if (x > 0) {
let result: number = x;
}
else {
result = -x; //error result is undefined here
}
return result; //error result is undefined here
}
In the case of for loops, if the loop variables are declared with let, different variable instances are defined for each loop iteration:
for (let i = 0; i < 5; i++) {
setTimeout(function(){ console.log(i) }, 1000);
}
A new variable named i is created at each iteration. So, we have five different variables with the values 0, 1, 2, 3, 4. Due to setTimeout, all variables are logged to the console after 1 second ( 1000 milliseconds), when the for loop is already ended. The five different copies of i remain unchanged and also retain their values after the for loop has ended, so the result in the console will be this:
>0
>1
>2
>3
>4
Now let's see by substituting let with var:
for (var i = 0; i < 5; i++) {
setTimeout(function(){ console.log(i) }, 1000);
}
Then there would be a unique i, whose scope is the function containing the for loop. Accordingly, after the loop ends, the value of this unique variable would be 5. Therefore, since all five occurrences of the setTimeout statement capture this variable, and since all values are logged after the end of the for loop, the result in the console will be this:
>5
>5
>5
>5
>5
As in C#, variables may always be redefined outside their scope, since variables defined this way are considered different:
for (let i = 0; i < 5; i++) {
setTimeout(function(){ console.log(i) }, 1000);
}
let i: string ="this is a string";
In a difference from C#, a new variable with the same name may also appear in the same scope. In this case, the newer definition overrides the previous one:
var firstName = "francesco";
var firstName = "peter"; //correct, new definition overrides previous one.
However, overrides are allowed only if the two variables have the same type: