function declaration after return statement global

2019-04-09 17:30发布

问题:

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.

回答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


回答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.



回答3:

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



回答4:

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.