JavaScript Function Scoping and Hoisting

Javascript function scoping and hoisting

Function hoisting means that functions are moved to the top of their scope. That is,

function b() {  
a = 10;
return;
function a() {}
}

will be rewritten by the interpeter to this

function b() {
function a() {}
a = 10;
return;
}

Weird, eh?

Also, in this instance,

function a() {}

behaved the same as

var a = function () {};

So, in essence, this is what the code is doing:

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); //alerts global variable "a"

How does this hoisting work with block scope?


According to the web compat semantics at the place of the function declaration, the value of the blocked scope variable is bound to the outer scope². This code is equivalent to:

let outerFoo; // the functions create a binding outside of the scope

{
let innerFoo; // but also inside
// due to hoisting, functions get bound before any code get's executed:
innerFoo = function foo() {
console.log('A');
};
innerFoo = function foo() {
console.log('B');
};

// At the place of the function declaration, the variable leaves the scope
/* function foo() {
console.log('A');
} */
outerFoo = innerFoo;

innerFoo();

innerFoo = 1;

// this also applies to the second declaration
/* function foo() {
console.log('B');
} */
outerFoo = innerFoo;

innerFoo = 2;

console.log(innerFoo);
}
console.log(outerFoo);

How JS hoisting works within functions?

JavaScript hoisting within functions means that the declaration of variables are moved to the top of the function block. When you enter foo(), var boo is redeclared instantly even though you have not reached it (because the JS engine knows that this declaration exists within the function). Accordingly, the reason that it is undefined is because it has only been declared, you don't assign a value until the following line.

In reality, this is not a situation you should find yourself in if you declare variables in an appropriate scope and don't redeclare variables with the same name, but I understand your curiosity.

You can read more about this here.

JavaScript 'hoisting'

  1. The global a is set to 1
  2. b() is called
  3. function a() {} is hoisted and creates a local variable a that masks the global a
  4. The local a is set to 10 (overwriting the function a)
  5. The global a (still 1) is alerted

Hoisting and variable scope

Variable declarations hoist to the top of the execution context, in this case the function users. Rewriting these to show how it looks from the hoisted perspective often clears up any confusion

var name = "Paul"; 
function users () {
var name;//<- hoisted variable declaration
if (!name) {
name = "Jack";
}
console.log(name);
}
users(); //outputs "Jack"

vs.

var name = "Paul"; 
function users () {
if (!name) {//no hoisted variable declaration, uses global
name = "Jack";
}
console.log(name);
}
users(); //outputs "Paul"

Execution contexts contain several key components, the most relevant here are the lexical environment and variable environment. I cover the differences between the two (and some brief history) in more depth if you are interested here: https://stackoverflow.com/a/32573386/1026459



Related Topics



Leave a reply



Submit