var a = 'why is this not undefined?';
function checkScope(a) {
var a;
console.log(a);
}
checkScope(a);
Javascript是功能范围语言,对吗?当我在与函数参数使用相同名称的函数内部声明一个新变量时,为什么新定义的变量仍然保存与参数相同的数据?
我认为它应该是未定义的?
答案 0 :(得分:41)
var a;
实际上是一个变量声明语句。定义函数时,在代码执行之前处理其中声明的所有变量,因此即使在运行时执行实际声明行之前也可以使用变量。这称为var
hoisting。因此,无论您声明一个变量多少次,该变量实际上只被声明一次。
在您的情况下,您已将a
定义为函数的参数之一,该函数的作用域为当前函数。然后你声明一个具有相同名称的变量。由于a
已在函数中声明,因此作为其中一个参数,var a;
声明将被忽略。
这就是你在控制台中获得why is this not undefined?
的原因。
而不是var a;
,假设您有var a = 1;
,在这种情况下,变量已经声明,但赋值表达式将在运行时和值{ {1}}将被分配到1
。因此,a
将打印console.log
。
此行为在ECMA脚本5.1规范的10.5 Declaration Binding Instantiation,
部分中进行了解释
- 醇>
如果代码是功能代码,那么
一个。设func是[[Call]]内部方法启动代码执行的函数。让名称为 func 的值 [[FormalParameters]]内部财产。
湾设 argCount 为args中的元素数。
℃。设 n 为数字0。
d。对于名称中的每个String argName ,按列表顺序执行
我。设 n 为 n 的当前值加1。
II。如果 n 大于 argCount ,请将 v 取消定义,否则让 v 为的值n args的元素。
III。 让 argAlreadyDeclared 是调用 env 的HasBinding具体方法传递 argName 作为参数的结果。
IV。 如果 argAlreadyDeclared 为false,请调用 env 的CreateMutableBinding具体方法,将 argName 作为 参数强>
v。调用 env 的SetMutableBinding具体方法,将 argName , v 和 strict 作为参数传递
...
- 醇>
对于代码中的每个 VariableDeclaration 和 VariableDeclarationNoIn d ,在源文本顺序中执行
一个。让 dn 成为 d 中的标识符。
湾让 varAlreadyDeclared 成为调用 env 的HasBinding具体方法传递 dn 作为参数的结果。
℃。 如果 varAlreadyDeclared 为false,则
我。 调用 env 的CreateMutableBinding具体方法,将 dn 和 configurableBindings 作为参数传递。
II。调用 env 的SetMutableBinding具体方法,将 dn ,undefined和 strict 作为参数传递。
正如我们在规范中看到的那样,函数中声明的参数和变量,实际上都是在与定义它们的函数相对应的执行环境中定义的。因此,如果参数和变量具有相同的名称,则该变量实际上只定义一次,而忽略第二个声明。
答案 1 :(得分:4)
您将变量a作为参数传递给函数检查。function checkScope(a) {
在函数内部,您再次尝试声明var a,var a;
这两个都在同一范围内,对吧?即函数check();
内部根据docs,函数内的var a
是你作为参数传递的同一个变量,你只是在声明之前使用它...你可以用JS做到这一点
所以你编写的代码与
是等价的var a = 'why is this not undefined?';
function checkScope(a) {
console.log(a);
}
checkScope(a);
,即var a被忽略。
你期望var a应该返回undefined然后代码就像这样
var a = 'why is this not undefined?';
function checkScope() {
var a
console.log(a);
}
checkScope();
这次我们没有将参数a传递给函数,并且在函数范围内创建了一个新的变量var a
,因此变得未定义
答案 2 :(得分:4)
该参数仍在函数内部定义,因为当变量已在同一范围内定义时,var a;
被忽略。
像var a;
这样的语句并不代表在代码中的那一点创建变量。所有变量声明都是hoisted到示波器的顶部,因此您可以在示波器中重新声明它们多次,并且它们仍然只创建一次。
如果声明具有赋值,例如var a = 2;
,则赋值发生在语句在代码中的位置,无论声明是否被忽略。
示例:
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);
&#13;
答案 3 :(得分:2)
因为JavaScript忽略了变量的重新声明。但是,如果您改为:
var a = 'why is this not undefined?';
function checkScope(a) {
var a = 'foo';
console.log(a);
}
checkScope(a);
a
的值将被覆盖。因为var a = 'foo';
由变量声明(var a;
)和值赋值(a = 'foo';
)组成;