Search code examples
javascriptfunctionvariablesscopehoisting

Javascript Couldn't understand a trick variable "hoisting": why it's NaN value?


I tried JavaScript to understand its hoisting strategy, but got more confused:

function f(i){this.i+=i}
i=2
f(3)
console.log(i)

It outputs

5

(1) This is what my expected. Then I tried to relocalte "i=2" statement:

function f(i){this.i+=i}
f(3)
console.log(i)
i=2

It outputs

NaN

(2) Why is that? I expected because "i" is hoisted to the front of the whole program, why it prints "NaN"? One possible answer is, the program is refactored by compiler to be:

var i
function f(i){this.i+=i}
f(3)
console.log(i)
i=2

(3) So when "console.log(i)", i has not be assigned any value, so it's "NaN"--->But I tried the program below:

function f(i){this.i+=i}
f(3)
i=2
console.log(i)

If the above explanation was correct, I expect this should also output "NaN". But in fact, it outputs

2

This is even more weird. Did "hoisting" worked at all in this case?

(4) More interestingly, if I change the program to be:

var i
function f(i){this.i+=i}
f(3)
console.log(i)
i=2

Then it outputs

undefined

Why is that?

(5) And for the program:

var i
function f(i){this.i+=i}
f(3)
i=2
console.log(i)

It again, outputs

2

Could you explain the above observations, as it really comes out of my understanding of what "hoisting" is?


Solution

  • One very important thing to remember is that Javascript will only hoist function declarations, not when you call a function.

    function f(i) { ... } //will be hoisted
    f(2); //won't be hoisted
    

    Moving on...

    I tried to relocalte "i=2" statement...It outputs NaN...Why is that? I expected because "i" is hoisted to the front of the whole program, why it prints "NaN"?

    function f(i){this.i+=i}
    f(3) //the function executes i = undefined+3, which is NaN
    console.log(i) //i is logged, which is currently NaN
    i=2 //i has the value of 2 assigned to it
    

    This outputs NaN because when a variable which is undefined is treated like a Number, it becomes NaN.

    I expect this should also output "NaN". But in fact, it outputs 2 This is even more weird. Did "hoisting" worked at all in this case?

    function f(i){this.i+=i}
    f(3) //the function executes i = undefined+3, which is NaN
    i=2 //i has the value of 2 assigned to it
    console.log(i) //i is logged, which is currently 2
    

    This outputs 2 because i is assigned the value of 2 just before i is logged.

    ...it outputs undefined Why is that?

    var i //i is undefined
    function f(i){this.i+=i} //f is hoisted and is line 1
    f(3) //the function assigns (undefined + 3) to a variable which is never referenced
    console.log(i) //i is logged, which is currently undefined
    i=2 //i has the value of 2 assigned to it
    

    This outputs undefined because i never had a value assigned to it before it was logged.

    It again, outputs 2

    var i //i is undefined
    function f(i){this.i+=i} //f is hoisted and is line 1
    f(3) //the function assigns (undefined + 3) to a variable which is never referenced
    i=2 //i has the value of 2 assigned to it
    console.log(i) //i is logged, which is currently 2
    

    This outputs 2 because i is assigned the value of 2 just before i is logged.