unexpected results with function and variable hoisting [duplicate]
Asked Answered
B

1

9

I'm reading the second book of the series "You don't know JS" and I've read that functions are hoisted before variables.

So this is the code:

foo(); // 1

var foo;

function foo() {
    console.log( 1 );
}

foo = function() {
    console.log( 2 );
};

The output of this will be 1. But why? Functions are hoisted first and then variables. So after my function foo (the one that prints 1) is hoisted it has to be followed by the variable foo. So the result should be "undefined" instead of "1".

I expect the code to behave as if it had been:

// hoisted first
function foo() {
    console.log( 1 );
}

// hoisted second
var foo;  // implicitly initialized to 'undefined'

foo();  // call 'undefined' - error?

foo = function() {
    console.log( 2 );
};

What's happening here?

Bivalent answered 26/5, 2018 at 7:13 Comment(1)
Ooh, subtle. I like this question.Coffee
E
9

As said, functions are hoisted before variables; if the interpterer comes across var foo after foo has already been defined in the scope, it will simply be ignored. It doesn't assign foo to undefined, it only ensures that a variable named foo exists in the current scope - which it already does.

As it says in your You Don't Know JS link:

multiple/duplicate var declarations are effectively ignored

Here's another commonly seen example of hoisted duplicate variables being ignored that might be more familiar/intuitive:

if (false)
  var foo = false;
else
  var foo = true;

turns into

var foo;
var foo; // does not actually do anything; does not assign `undefined` to `foo`, ignored
// foo just *happens* to not have anything assigned to it in almost all cases like this
if (false)
  foo = false;
else
  foo = true;
Eolic answered 26/5, 2018 at 7:24 Comment(6)
But even if I set the variable to a function expression I will again get the result 1.Bivalent
@Bivalent You already set the variable to a function expression in your original code. What do you mean?Coffee
@BoSsYyY, that assignment is not hoisted: it happens after you have called the function.Customs
Yes I know that assignment is not hosted. But look at this example: foo(); // 1 var foo = function() { console.log("2"); }; function foo() { console.log( 1 ); } here variable "foo" will be hoisted then the function expression should be assigned to it (but it isn't) and then exectuted. But the result is still 1Bivalent
@Bivalent Function declarations are hoisted; function expressions (with =) are not. That is assignment, so calling foo before the assignment results in 1.Eolic
Oh yes. Got it. the assignment is going to happen after the function call.Bivalent

© 2022 - 2024 — McMap. All rights reserved.