Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

function declaration after return statement global variable is not overwritten [duplicate]

I have a Javascript code as below, http://jsfiddle.net/ramchiranjeevi/63uML/

var foo = 1;
function bar() {
    foo = 10;
    return;
    function foo() {}   
}

bar();
console.log(foo);  // returns 1

When the code executed, the bar() function is called and the global variable is overwritten with value 10, then the log should be printed as 10 instead it is printed as value 1.

like image 554
Jeevi Avatar asked Nov 27 '13 13:11

Jeevi


2 Answers

Because of a concept called "hoisting", function declarations are "moved" to the top of the scope.

When that happens, a new foo context is created within the local scope. The assignment of 10 later affects the localized scope and not the variable from the parent scope.

You can see the same behavior if you declare a block-local variable called foo with the var keyword:

var foo = 1;
function bar() {
    var foo = 10; // this is, functionally,
    return;       // the same as declaring a function in this scope named foo
}

bar();
console.log(foo); // output: 1

http://jsfiddle.net/GRMule/8F5K3/

Another example, breaking it down

var foo = 1;
function bar() {
    console.log(foo); // because of hoisting, you will get "function" as output
    foo = 10;         // you just over-wrote the block-local foo, the function
    return;
    function foo () {} // this is "hoisted" to the top of this scope, 
                       // creating a new "foo" context
}

You can use the var method of declaring functions to stop it from hoisting, but you would generally avoid re-using names like this instead, to keep your code maintainable:

var foo = 1;
function bar() {
    console.log(foo); // undefined
    foo = 10;
    return;
    var foo = function () {};
}
bar();
console.log(foo); // 1

http://jsfiddle.net/znrG2/

... but as you can see, once you use the var word in a scope block, the existence of that local context is hoisted, if not the value, and any variable with the same name from the parent scope will not be accessible or affected in the current scope.

Similarly, functions and variables declared in a scope using this, as in this.foo = function () {}; do not hoist: http://jsfiddle.net/8F5K3/3/

Most importantly, though, functions or variables declares using this don't overwrite variable contexts from the parent scope. You can use that fact to avoid this functionality in the language, if you absolutely need to reuse the name "foo":

var foo = 1;
function bar() {
    console.log(foo); // 1
    foo = 10;
    return;
    this.foo = function () {};
}
bar();
console.log(foo); // 10

http://jsfiddle.net/znrG2/1/

Related Reading

  • Explaining function and variable hoisting in JavaScript - http://jamesallardice.com/explaining-function-and-variable-hoisting-in-javascript/
  • Scope Cheatsheet on MDN - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Scope_Cheatsheet
  • Functions and function scope on MDN - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope
like image 80
Chris Baker Avatar answered Oct 05 '22 23:10

Chris Baker


This is javascript hoisting behavior. Take a look at this link. In your case, the script is interpreted like this:

var foo = 1;
function bar() {
    function foo() {}
    foo = 10;
    return; 
}

bar();
console.log(foo);

Because:

Function declarations and variable declarations are always moved (“hoisted”) invisibly to the top of their containing scope by the JavaScript interpreter

In your case, when you assign foo = 10;, you're assigning to the local variable. That's why the global variable is still unchanged.

like image 37
Khanh TO Avatar answered Oct 05 '22 23:10

Khanh TO