8

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.

Ram G Athreya
  • 4,892
  • 6
  • 25
  • 57
Jeevi
  • 1,052
  • 1
  • 10
  • 22

4 Answers4

8

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

Chris Baker
  • 49,926
  • 12
  • 96
  • 115
2

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.

Khanh TO
  • 48,509
  • 13
  • 99
  • 115
1

function foo() {} defined in local bar() scope, so if you redefine foo() in bar() it change local scope variable but not global

Vladimir Gordienko
  • 3,260
  • 3
  • 18
  • 25
  • thanks for your reply, but the function foo() {} is after return statement, it will not be reachable when the bar() function is called. Then again when you put a log before the return statement the value printed is 10. Then how come the global variable is not overwritten. – Jeevi Nov 27 '13 at 13:15
  • No matter where you declare foo() in scope; functions declaration runs in first time always, before code runs – Vladimir Gordienko Nov 27 '13 at 13:16
  • @Jeevi: that's because of hoisting. Take a look at my answer – Khanh TO Nov 27 '13 at 13:18
  • I just note what code after " the script is interpreted like this:" have no differences with code in question – Vladimir Gordienko Nov 27 '13 at 13:19
  • @Jeevi: if you look closely, you would see that the function declaration comes first in my answer – Khanh TO Nov 27 '13 at 13:21
  • @VladimirGordienko Yes, it does. Read more carefully :) – Chris Baker Nov 27 '13 at 13:21
-1
function bar() {
  foo = 10;  // define global variable named foo
  return;    // the function return value is "undefined"
  function foo() {}   // define a function named "foo" inside bar function, which means `foo = 10` inside function bar() becomes local variable declaration because "foo" is already defined.
}

So the global variable foo is not impacted at all.

shawnzhu
  • 7,233
  • 4
  • 35
  • 51