我记得变量是Javascript中的函数作用域。但是,如果我在循环中重新定义局部变量,行为如何。一个常见的用例是嵌套循环。 在下面的代码中,如果我将j更改为i,则外部for循环在一次迭代后终止,因为外部作用域中的i值与inner for循环相同。由于我使用var,我期待(类似于其他语言)它在内部fo循环中被重新定义。这是否意味着在JS中,没有办法在函数范围内重新声明和使用局部变量。
for (var i = 0, len = x.length; i < len; i++) {
...
for (var j = 0, len = y.length; j < len; j++) {
...
}
}
答案 0 :(得分:8)
正如你所说,JavaScript只有功能范围。变量声明被提升到声明它们的作用域的顶部。您的示例解释如下:
var i, j, len; //Declarations are hoisted...
for (i = 0, len = x.length; i < len; i++) { //Assignments happen in place
for (j = 0, len = y.length; j < len; j++) {
}
}
至于这一部分:
如果我将j更改为i,则外部for循环在一次迭代后终止
如果将j
替换为i
,则在内循环的第一次迭代后,i
将为y.length - 1
,外循环将继续或停止,取决于x.length
和y.length
之间的差异。
如果您对内部运作的真实解释感兴趣,ECMAScript spec (Declaration Binding Instantiation)会详细介绍它。总而言之,每次控件进入新的执行上下文时,都会发生以下情况(比这更多,但这是其中的一部分):
对于代码中的每个 VariableDeclaration 和 VariableDeclarationNoIn d , 源文本顺序
- 让 dn 成为 d 中的标识符。
- 让 varAlreadyDeclared 成为调用 env的 HasBinding具体的结果 传递 dn 作为参数的方法。
- 如果 varAlreadyDeclared 为false,则
- 调用 env的 CreateMutableBinding传递 dn 的具体方法 configurableBindings 作为参数。
- 调用 env的 SetMutableBinding 具体方法传递 dn ,undefined和 strict 作为参数。
这意味着如果每个执行上下文多次声明一个变量,它将被有效地忽略。
答案 1 :(得分:4)
每个var
声明都会放在当前范围的顶部,因此您的代码与以下内容相同:
var i, j, len;
for (i = 0, len = x.length; i < len; i++) {
...
for (j = 0, len = y.length; j < len; j++) {
...
}
}
答案 2 :(得分:0)
JS中没有块级范围。
但是,如果最需要在代码中声明/重新声明相同的变量名称,则可以执行以下操作:
function loopIt(arr, fn, scope) {
for (var i = 0, len = arr.length; i < len; i++) {
fn.call(scope || this, arr[i], i, arr);
}
}
并使用它:
var firstArr = ["a", "b"];
var secondArr = ["c", "d"];
loopIt(firstArr, function(item, i) {
var msg = "Hey it's '" + item + "'";
console.log(msg);
// if you want access to the parent scope's var
var scopedItem = item;
loopIt(secondArr, function(item, i) {
var msg = "Hello it's '" + item + "' in '" scopedItem + "'";
console.log(msg);
});
});
这将给我们带来以下结果:
Hey it's 'a'
Hello it's 'c' in 'a'
Hello it's 'd' in 'a'
Hey it's 'b'
Hello it's 'c' in 'b'
Hello it's 'd' in 'b'