I just read a great article about JavaScript Scoping and Hoisting by Ben Cherry in which he gives the following example:
var a = 1;
function b() {
a =
Hoisting is behavioural concept of JavaScript. Hoisting (say moving) is concept that explains how and where variables should be declared.
In JavaScript, a variable can be declared after it has been used because Function declarations and variable declarations are always moved (“hoisted”) invisibly to the top of their containing scope by the JavaScript interpreter.
We encounter two types of hoisting in most cases.
1.Variable declaration hoisting
Lets understand this by this piece of code.
a = 5; // Assign 5 to a
elem = document.getElementById("demo"); // Find an element
elem.innerHTML = a; // Display a in the element
var a; // Declare a
//output-> 5
Here declaration of variable a will be hosted to top invisibly by the javascript interpreter at the time of compilation. So we were able to get value of a. But this approach of declaration of variables is not recommended as we should declare variables to top already like this.
var a = 5; // Assign and declare 5 to a
elem = document.getElementById("demo"); // Find an element
elem.innerHTML = a; // Display a in the element
// output -> 5
consider another example.
function foo() {
console.log(x)
var x = 1;
}
is actually interpreted like this:
function foo() {
var x;
console.log(x)
x = 1;
}
In this case x will be undefined
It does not matter if the code has executed which contains the declaration of variable. Consider this example.
function foo() {
if (false) {
var a = 1;
}
return;
var b = 1;
}
This function turns out to be like this.
function foo() {
var a, b;
if (false) {
a = 1;
}
return;
b = 1;
}
In variable declaration only variable definition hoists, not the assignment.
Unlike the variable hoisting the function body or assigned value will also be hoisted. Consider this code
function demo() {
foo(); // this will give error because it is variable hoisting
bar(); // "this will run!" as it is function hoisting
var foo = function () {
alert("this would not run!!");
}
function bar() {
alert("this will run!!");
}
}
demo();
Now as we understood both variable and function hoisting, let's understand this code now.
var a = 1;
function b() {
a = 10;
return;
function a() {}
}
b();
alert(a);
This code will turn out to be like this.
var a = 1; //defines "a" in global scope
function b() {
var a = function () {}; //defines "a" in local scope
a = 10; //overwrites local variable "a"
return;
}
b();
alert(a);
The function a() will have local scope inside b(). a() will be moved to top while interpreting the code with its definition (only in case of function hoisting) so a now will have local scope and therefore will not affect the global scope of a while having its own scope inside function b().
Hoisting In JavaScript means, variable declarations are executed through out the program before any code is executed. Therefore declaring a variable anywhere in the code is equivalent to declaring it at the beginning.
Here's my recap of the answer with more annotation and an acompaniying fiddle to play around with.
// hoisting_example.js
// top of scope ie. global var a = 1
var a = 1;
// new scope due to js' functional (not block) level scope
function b() {
a = 10; // if the function 'a' didn't exist in this scope, global a = 10
return; // the return illustrates that function 'a' is hoisted to top
function a(){}; // 'a' will be hoisted to top as var a = function(){};
}
// exec 'b' and you would expect to see a = 10 in subsequent alert
// but the interpreter acutally 'hoisted' the function 'a' within 'b'
// and in doing so, created a new named variable 'a'
// which is a function within b's scope
b();
// a will alert 1, see comment above
alert(a);
https://jsfiddle.net/adjavaherian/fffpxjx7/
The function a
is hoisted inside function b
:
var a = 1;
function b() {
function a() {}
a = 10;
return;
}
b();
alert(a);
which is almost like using var
:
var a = 1;
function b() {
var a = function () {};
a = 10;
return;
}
b();
alert(a);
The function is declared locally, and setting a
only happens in the local scope, not the global var.
Long Post!
But it will clear the air!
The way Java Script works is that it involves a two step process:
Compilation(so to speak) - This step registers variables and function declarations and their respective scope. It does not involve evaluating function expression: var a = function(){}
or variable expression (like assigning 3
to x
in case of var x =3;
which is nothing but the evaluation of R.H.S part.)
Interpreter: This is the execution/evaluation part.
Check the output of below code to get an understanding:
//b() can be called here!
//c() cannot be called.
console.log("a is " + a);
console.log("b is " + b);
console.log("c is " + c);
var a = 1;
console.log("Now, a is " + a);
var c = function() {};
console.log("Now c is " + c);
function b() {
//cannot write the below line:
//console.log(e);
//since e is not declared.
e = 10; //Java script interpreter after traversing from this function scope chain to global scope, is unable to find this variable and eventually initialises it with value 10 in global scope.
console.log("e is " + e) // works!
console.log("f is " + f);
var f = 7;
console.log("Now f is " + f);
console.log("d is " + d);
return;
function d() {}
}
b();
console.log(a);
Lets break it:
In the compilation phase,
'a' would be registered under global scope with value 'undefined
'.
Same goes for 'c
', its value at this moment would be 'undefined
' and not the 'function()
'.
'b
' would be registered as a function in the global scope.
Inside b
's scope, 'f
' would be registered as a variable which would be undefined at this moment and function 'd
' would be registered.
When interpreter runs, declared variables and function()
(and not expressions) can be accessed before the interpreter reaches the actual expression line. So, variables would be printed 'undefined
' and declared anonymous function can be called earlier. However, trying to access undeclared variable before its expression initialisation would result in an error like:
console.log(e)
e = 3;
Now, what happens when you have variable and function declaration with same name.
Answer is - functions are always hoisted before and if the same name variable is declared, it is treated as duplicate and ignored. Remember, order does not matter. Functions are always given precedence. But during evaluation phase you can change the variable reference to anything (It stores whatever was the last assignment) Have a look at the below code:
var a = 1;
console.log("a is " + a);
function b() {
console.log("a inside the function b is " + a); //interpreter finds 'a' as function() in current scope. No need to go outside the scope to find 'a'.
a = 3; //a changed
console.log("Now a is " + a);
return;
function a() {}
}
var a; //treated as duplicate and ignored.
b();
console.log("a is still " + a + " in global scope"); //This is global scope a.
What you have to remember is that it parses the whole function and resolves all the variables declarations before executing it. So....
function a() {}
really becomes
var a = function () {}
var a
forces it into a local scope, and variable scope is through the entire function, so the global a variable is still 1 because you have declared a into a local scope by making it a function.