About
Variable scope in Javascript.
variable scope is delimited by the function definition, not a the block level
A block has the scope of its inner function.
As a function is also an object, by generalization, the scope is at the object level.
The keyword this gives access to this scope object.
There is an exception to the function ruling scope and this is with a caught exception variable in a try…catch block. This variable is scoped only to the try..catch block. See Javascript - Exception Handling with the Error object
Lexical environment / Scope chain
In the ES5 specification, the scope diagram is called the lexical environment (or scope chain in older versions of the standard).
Javascript looks the variables:
- first down in the prototype chain
- then up in the scope, starting with the innermost scope and working its way outward.
Example: for the below code,
function pointsOnCircle(n){
var point = new Point(x,y);
...
}
the scope diagram can be represented as;
where:
- global is the global object
- new Point is a constructor
- that have a prototype
- that have the root prototype Object.prototype
Scope and
Block
The scope is not at the block level.
Meaning that the variable declared in the for loop (a block) exists also outside the loop. If you want to restraint the scope of a variable, you need to create it inside a function.
Variable
A variable declared in a script without function is declared in the global namespace which is the top variable context space.
Declaring a variable anywhere in a block code (or script) is equivalent to declaring it at the top of its scope (or script). See hoisting
Hoisting
Declaring a variable anywhere in a block code (or script) is equivalent to declaring it at the top of its scope (or script)
Variable declarations are hoisted up to the top of the context (script, function,…) in which they reside.
hoisting means moving the var declaration to the top of its enclosing scope. Technically, this process is explained by how code is compiled,
foo = 2
var foo;
is treated as:
var foo;
foo = 2
Example:
function noHoisting(){
bar = "global variable declaration because without the var keyword in a function";
}
// Run the function to run the variable declaration
noHoisting();
console.log(bar);
function hoisting(){
bar = "local variable declaration because declared below with the var keyword";
// thanks to variable hoisting the below statement will placed at the top of its scope (ie the actual function)
// and the variable will not be considered global anymore but local
var bar;
console.log(bar);
}
hoisting();
console.log(bar);
Management
Creation
IIFE
To force the creation of a local scope, a nested function must be created and called right away. This technique is known as the immediately invoked function expression, or IIFE and is an indispensable workaround for JavaScript’s lack of block scoping.
Example:
(function IIFE(){
var foo = "IFFE variable";
console.log( "Hello!" );
})(); // "Hello!"
// foo is not defined in the global scope
if (typeof foo == 'undefined') {
console.log("foo is undefined");
}
Modification
Statement
Two statements can modify the actual lexical scope:
Restriction
An IIFE is often used to create a scope in order to declare variables that won’t affect the surrounding code outside of it. See IIFE
Webtool (Chrome)
Example
var x = 0; // x is a global variable created then in the global namespace.
var y = 1;
console.log("The global variable x has been declared with the value "+x+".");
console.log("The global variable y has been declared with the value "+y+".");
function f(){
var x = 1; // x is declared locally in the function. There is the two x variables: The first one global and the second one local
x = 2; // This modification will not impact the global variable
console.log("The local variable x has the value "+x);
y = 2; // This modification will impact the global variable because z is not declare with the var symbol.
z = x; // z is NOT declared locally with the var keyword. z will then leak outside of the function
}
f(); // Execute function f
console.log("The global variable x has still the value "+x+", the function got no impact on it"); // 0
console.log("The global variable y has the value "+y+", it has been changed in the function because it was not declared locally with the var keyword");
console.log("The variable z has the value "+z+", has leaked from the function because it was not declared with the var keyword it has a global scope");