问题
The output is 15 (in f, x is taken to be 10 and y is 7) with the following:
var x = 5;
function f(y) { return (x + y) - 2};
function g(h) { var x = 7; return h(x) };
{ var x = 10; z = g(f); console.log(z) };
Why did x take the value from the 4th line and not from the 1st line (and why not the 3rd line)?
回答1:
var
s are not blocked scoped, so the last line is equivalent to
x = 10; z = g(f); console.log(z)
It should be clearer now that the value of x
was changed to 10
before f
was executed.
It is also important to note that free variables are evaluated when a function is called, not when it was defined. And of course the value of a variable can change between the definition of a function and the call of the function, just like in your example.
In the third line, x
is local to g
and therefore is completely independent from the "outer" variable x
.
See also What is the scope of variables in JavaScript?
A much simpler example that demonstrates this behavior would be:
var x = 5;
function foo() {
console.log(x);
}
x = 10;
foo(); // outputs 10
回答2:
var x = 5;
function f(y) { return (x + y) - 2};
function g(h) { var x = 7; return h(x) };
{ var x = 10; z = g(f); console.log(z) };
is a bit of a mess, so let's clean it up:
/* 1 */var x = 5;
/* 2 */
/* 3 */function f(y) {
/* 4 */ return (x + y) - 2
/* 5 */};
/* 6 */
/* 7 */function g(h) {
/* 8 */ var x = 7;
/* 9 */ return h(x)
/* 10 */};
/* 11 */
/* 12 */{
/* 13 */ var x = 10;
/* 14 */ z = g(f);
/* 15 */ console.log(z)
/* 16 */};
This still has a number of issues which I copied verbatim. All I did was add whitespace. Now I'm going to clean up the code so that it expresses the actual execution order.
// variable and function declaration happens before assignment
// variables are scoped to their containing function,
// or, when no parent function exists, to global scope
var x;
function f(y) {
// cleaned up semicolon usage (lines 4 & 5)
// while JavaScript's automatic semicolon insertion would work
// it's generally better to be explicit about intent
return x + y - 2;
}
function g(h) {
// again separated variable declaration from assignment
// from line 8 above
var x;
x = 7;
return h(x);
}
// removed unnecessary block scope from lines 12 & 16
// variable assignment now can happen after declaration
// x is assigned from line 1 above
x = 5;
// x is subsequently overwritten from line 13 above as
// JS variables don't have block scope
// duplicate var declaration has no effect and is removed
x = 10;
z = g(f);
console.log(z);
Now that the code is properly formatted, it's immediately clear that x
will have a value of 10
because the execution order leads to x
being overwritten.
回答3:
In javaScript, there is nothing called block level scope. It is treated same as global variable. Now let's analyze these statements and their scope. Initially, you have declared var x = 5;. Then you have defined two functions and then again you have defined var x = 10;. Please note that JavaScript will override the value of x. Now x is 10 globally.
Now you have declared z = g(f); You are passing a function as a parameter. Inside g, you have declared x again as var x = 7;. Please note that the variable defined inside a function has the higher preference than the same variable name declared in the global scope and also the current value of the variable is visible only to this function. Outside g, everyone knows that x is 10.But inside g, value of x will be 7.
Now, you have returned h(x); this means you are calling f(y) as f(7); f still knows that x is 10 globally and doesn't have any idea whether it even existed inside function g. So f computes (10 + 7) - 2. Hence the value of z becomes 15.
For clarification, I would recommend you to use the debugger present in the browser tools. Debug each line and understand how the scope works. Hope it helps.
来源:https://stackoverflow.com/questions/37444006/javascript-scoping-of-variables