88

I came across JavaScript 'hoisting' and I didn't figure out how this snippet of code really functions:

var a = 1;

function b() {
    a = 10;
    return;

    function a() {}
}

b();
alert(a);

I know that function declaration like ( function a() {} ) is going to be hoisted to the top of the function b scope but it should not override the value of a (because function declarations override variable declarations but not variable initialization) so I expected that the value of the alert would be 10 instead of 1!!

David G
  • 94,763
  • 41
  • 167
  • 253
morfioce
  • 1,107
  • 2
  • 9
  • 12
  • Hoisting is JavaScript's default behavior of moving declarations to the top. *(function declarations are "moved" from where they appear in the flow of the code to the top of the code. This gives rise to the name "Hoisting".)* [Read more](https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20%26%20closures/ch4.md) – Mohammad Kermani Sep 06 '16 at 11:51
  • Here is a link with easy explanation about "Function expressions vs. function declarations and Hoisting" ... https://gomakethings.com/function-expressions-vs-function-declarations/ – S. Mayol Oct 12 '18 at 02:12

5 Answers5

117
  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
Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
6

It's because the order of compilation/interpretation in this example is somewhat misleading. The function a () {} line is interpreted before any of the rest of the function is executed, so at the very beginning of the function, a has the value of function a () {}. When you reassign it to 10, you are reassigning the value of a in the local scope of function b(), which is then discarded once you return, leaving the original value of a = 1 in the global scope.

You can verify this by placing alert()s or the like in the appropriate places to see what the value of a is at various points.

fraveydank
  • 71
  • 2
5

(1) JavaScript does not have block statement scope; rather, it will be local to the code that the block resides within.

(2) Javascript's declaration of variables in a function scope, meaning that variables declared in a function are available anywhere in that function, even before they are assigned a value.

(3) Within the body of a function, a local variable takes precedence over a global variable with the same name. If you declare a local variable or function parameter with the same name as a global variable, you effectively hide the global variable.

you code is same as: (read comment)

<script>
var a = 1;          //global a = 1
function b() {
    a = 10;         
    var a = 20;     //local a = 20
}
b();
alert(a);           //global a  = 1
</script>

reference:
(1) JavaScript Variable Scope:
(2) A Dangerous Example of Javascript Hoisting
(3) Variable scope

So in your code:

var a = 1;          //global a = 1  
function b() {
    a = 10;         
    return;
    function a() {} //local 
}
b();
alert(a);           //global a = 1  
Grijesh Chauhan
  • 57,103
  • 20
  • 141
  • 208
  • where you wrote "local a Undefined" - that's actually not true. function declarations are parsed before any content of the parent scope, so in this case when you assign a = 10, you are already overriding function a() {} with value 10. See Quentin's answer – Piotr Rochala Mar 11 '13 at 21:54
  • @rochal No, please read this article [Javascript hoisting can be especially nefarious in loops](http://thecomputersarewinning.com/post/a-dangerous-example-of-javascript-hoisting/) Also check code on safari browser...let me know And Yes its `a=10` on most browser ..Actually Undefined behaviour not ERROR – Grijesh Chauhan Mar 12 '13 at 04:12
  • read point 4. from Quentin's answer. At this point `a` already exists - it's a function, not an Undefined. How would Safari be different to i.e. Chrome..? – Piotr Rochala Mar 12 '13 at 09:08
  • @rochal `variables declared in a function are available anywhere in that function, even before they are assigned a value` I also checked it, and giving `10` But according to three tutorials (*I given link*) it should be undefined and 10 is result because of undefined. Quentin answered according to output but I think it may be not 10 for some browsers.. – Grijesh Chauhan Mar 13 '13 at 04:15
  • once again, in your example code: `a = 10; //local a Undefined` is _incorrect_ `a = 10; //local a is function(){} ` is correct because as soon as you check the value of a inside function b() it already has been overridden by the local function a(){} so your comment that "local a Undefined" is not valid. And browser has nothing to do with it, it's a language feature. – Piotr Rochala Mar 13 '13 at 04:39
  • @rochal Yes actually you are Correct it shouldn't be a browser Issue. **Corrected** The link: confused me [A Dangerous Example of Javascript Hoisting](http://thecomputersarewinning.com/post/a-dangerous-example-of-javascript-hoisting/) Do you understands what it says by Undefined **?** – Grijesh Chauhan Mar 15 '13 at 15:21
2
  1. function declaration function a(){} is hoisted first, hence in local scope a is created.
  2. If you have two variable with same name (one in global another in local), local variable always get precedence over global variable.
  3. When you set a=10, you are setting the local variable a , not the global one.

Hence, the value of global variable remain same and you get, alerted 1

Jhankar Mahbub
  • 9,746
  • 10
  • 49
  • 52
0

When I read the same article you did JavaScript Scoping and Hoisting, I was confused as well because the author never showed what the two opening example codes are interpreted as in the compiler.

Here is example you provided, and the second on the page:

var a = 1;
function b() {
    function a() {} // declares 'a' as a function, which is always local
    a = 10;
    return;
}
b();
alert(a);

and here is the first example on the page:

var foo = 1;
function bar() {
    var foo; // a new local 'foo' variable
    if (!foo) {
        foo = 10;
    }
    alert(foo);
}
bar();

Hope this helps

Jonathan
  • 3,893
  • 5
  • 46
  • 77