3

Can someone explain to me why (1) returns 11 where (2) returns undefined. what is the effect of function blocks/declarations to hoisting ?

// (1)
var boo = 11
console.log(boo) // 11
var boo = 10

// (2)
var boo = 11
function foo() {
   console.log(boo)
   var boo = 10
}
foo() // undefined
Fahd Lihidheb
  • 671
  • 4
  • 20

4 Answers4

6

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.

AJ_
  • 1,455
  • 8
  • 10
  • i thought the result of hoisting will be declaring boo then initializing it to 11 before exucuting the function, as it is lexically before the execution. PS: i was messing with JS, it is not prod code. – Fahd Lihidheb Jun 17 '20 at 15:38
  • Yea I figured and it's a good question, this seems like unexpected behaviour. – AJ_ Jun 17 '20 at 15:40
  • The introduction of `let` and `const` declarations improved this behavior considerably. I wouldn't go so far as to say never to use `var`, but it's usually better to use `let` or `const`. – Pointy Jun 17 '20 at 15:44
  • yes, but is this case it has something to do with declaring the function. – Fahd Lihidheb Jun 17 '20 at 15:46
2

var declaration (contrary to let) is always done at the top of its block, meaning:

var boo = 11
function foo() {
   console.log(boo)
   var boo = 10
}
foo()

is equal to

var boo = 11
function foo() {
   var boo // undefined
   console.log(boo)
   boo = 10 // 10
}
foo()
Alkaniszt
  • 43
  • 1
  • 6
  • what about the global boo ? – Fahd Lihidheb Jun 17 '20 at 15:47
  • 1
    As soon as `var boo` is declared in the local scope, you can't access the global boo anymore from inside the function. But the global boo in itself remains intact: `console.log(boo)` outside the function still outputs 11. – Alkaniszt Jun 17 '20 at 15:52
0

don't use var all the time after the first time you need to overwrite the boo

EDIT: it's undefined because you are declaring it twice

only 2 works fine if declared once and then overwritten in the function

// (1)
var boo = 11
console.log(boo) // 11
 boo = 10

// (2)
var boo = 11
function foo() {
   console.log(boo)
   boo = 10
}
foo() // 11

If you want to overDeclare in a function and call you need to console it after declaration at least

    // (2)
    var boo = 11
    function foo() {
       boo = 10
       console.log(boo)
    }
    foo() // 10
  • I know, i just want to know why each code behave differently. – Fahd Lihidheb Jun 17 '20 at 15:30
  • I thought this was correct as well. but it still works if only the boo inside of the foo() function has the var removed – JaySnel Jun 17 '20 at 15:33
  • 1
    @Nairi Areg Hatspanyan, there is nothing wrong with the code! i just need explanation. – Fahd Lihidheb Jun 17 '20 at 15:36
  • Ah, it's behaving so because you didn't assign it a value inside a function it has been declared but in js functions work so that if you have a function outside of it it is being like auto declareing with `undefined` value and then you should give it one – Nairi Areg Hatspanyan Jun 17 '20 at 15:40
0

Hoisting happens on every execution context. During the hoisting variable or function declarations are not moving to the top, they are just being written to the memory.

When you run a javascript file, first global execution context is created. Global execution context gives global object, "this" keyword and hoists the var declarations and function declarations.

in the first part of your question:

var boo = 11
console.log(boo) // 11
var boo = 10

boo is hoisted like this:

var boo=undefined. 

Because variables are PARTIALLY hoisted. var boo=10 is not going to overwrite var boo=undefined. this is how it looks like after hoisting:

var boo=undefined
    boo = 11
    console.log(boo) // it is clear why 11
    var boo = 10

in the second part of your question:

var boo = 11
function foo() {
   console.log(boo)
   var boo = 10
}
foo() 

var boo in the global context is partially hoisted.

var boo=undefined

but this is not relevant to us. Because when we create a new function and invoke it, a new execution context is created and inside this execution context another hoisting takes place like this:

function foo() {
   var boo=undefined  
   // "boo" is partially hoisted inside  
   // "boo" is written into the variable environment of the execution context
   // "foo()" will always look into the its variable environment first
   console.log(boo)
   boo = 10
}

we defined a variable more than once but in different scopes. we have var boo =11 in parent scope and var boo=10 in the local scope. this is an example of variable shadowing. foo() will be using the local variable first, so local variable is shadowing over the parent's value.

Yilmaz
  • 35,338
  • 10
  • 157
  • 202