问题
var a = 'why is this not undefined?';
function checkScope(a) {
var a;
console.log(a);
}
checkScope(a);
Javascript is functional scope language, right? When I declare a new variable just inside the function that uses the same name as the functional argument, why does the newly defined variable still hold the same data as the argument?
I thought it should be undefined?
回答1:
var a;
is actually a variable declaration statement. When the function is defined, all the variables declared in it, are processed before the code execution and so you can use the variables even before the actual declaration line is executed at runtime. This is called var hoisting. So, no matter how many times you declare a variable, the variable is actually declared only once.
In your case, you have defined a
as one of the parameters to the function, which is scoped to the current function. And then you are declaring a variable with the same name. Since a
is already declared in the function, as one of the parameters, the var a;
declaration will be ignored.
That is why you are getting why is this not undefined?
in the console.
Instead of var a;
, lets say you had var a = 1;
, in this case, the variable is already declared but the assignment expression will be evaluated at runtime and the value 1
will be assigned to a
. So, the console.log
will print 1
.
This behaviour is explained in the ECMA Script 5.1 Specification, under the section 10.5 Declaration Binding Instantiation,
If code is function code, then
a. Let func be the function whose [[Call]] internal method initiated execution of code. Let names be the value of func’s [[FormalParameters]] internal property.
b. Let argCount be the number of elements in args.
c. Let n be the number 0.
d. For each String argName in names, in list order do
i. Let n be the current value of n plus 1.
ii. If n is greater than argCount, let v be undefined otherwise let v be the value of the n’th element of args.
iii. Let argAlreadyDeclared be the result of calling env’s HasBinding concrete method passing argName as the argument.
iv. If argAlreadyDeclared is false, call env’s CreateMutableBinding concrete method passing argName as the argument.
v. Call env’s SetMutableBinding concrete method passing argName, v, and strict as the arguments.
....
For each VariableDeclaration and VariableDeclarationNoIn d in code, in source text order do
a. Let dn be the Identifier in d.
b. Let varAlreadyDeclared be the result of calling env’s HasBinding concrete method passing dn as the argument.
c. If varAlreadyDeclared is false, then
i. Call env’s CreateMutableBinding concrete method passing dn and configurableBindings as the arguments.
ii. Call env’s SetMutableBinding concrete method passing dn, undefined, and strict as the arguments.
As we see in the specification, the arguments and the variables declared in the function, all are actually defined in the execution environment corresponding to the function in which they are defined. So, if the arguments and the variables have the same name, the variable is actually defined only once and the second declaration is ignored.
回答2:
The parameter is still defined inside the function, becase the var a;
is ignored when the variable is already defined inside the same scope.
A statement like var a;
doesn't mean that the variable is created at that point in the code. All variable declarations are hoisted to the top of the scope, so you can redeclare them as many times you want in the scope, and they are still only created once.
If a declaration has an assignment though, like var a = 2;
, the assignment happens where the statement is in the code, regardless if the declaration is ignored or not.
Example:
function check(a) {
// both a and b exist here
document.write('a = ' + a + ', b = ' + b + '<br>');
var b = 1;
document.write('a = ' + a + ', b = ' + b + '<br>');
var a = 2; // not recreated, but assigned
document.write('a = ' + a + ', b = ' + b + '<br>');
}
check(42);
回答3:
you are passing the variable a to the function check as a parameter.
function checkScope(a) {
inside the function you are again trying to declare var a,
var a;
Both of these are within the same scope, right? i.e both inside the function check();
And according to docs, that var a
inside the function is same variable which you passed as parameter and you are just using it before declaration... you can do it with JS
So the code you have written is equuivalent to
var a = 'why is this not undefined?';
function checkScope(a) {
console.log(a);
}
checkScope(a);
i.e the var a is just ignored.
And what you expect that var a should return undefined then the code would be like this
var a = 'why is this not undefined?';
function checkScope() {
var a
console.log(a);
}
checkScope();
This time we are not passing the parameter a to the function and a new variable var a
is created within the function scope, thus becomes undefined
回答4:
Because JavaScript ignores redeclarations of variables. However, if you had this instead:
var a = 'why is this not undefined?';
function checkScope(a) {
var a = 'foo';
console.log(a);
}
checkScope(a);
The value of a
would be overwritten. Because var a = 'foo';
is composed by a variable declaration (var a;
) and a value assignment (a = 'foo';
);
This behaviour is described in the MDN docs.
来源:https://stackoverflow.com/questions/27963214/why-is-the-function-argument-not-overwritten-on-creating-variable-of-same-name-i