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.
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
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.
function foo() {} defined in local bar() scope, so if you redefine foo() in bar() it change local scope variable but not global
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.