在具有多个循环的函数中使用 var?

Using var in functions with multiple loops?

引自书本JavaScript: The Definitive Guide

Unlike variables declared with let, it is legal to declare the same variable multiple times with var. And because var variables have function scope instead of block scope, it is actually common to do this kind of redeclaration. The variable i is frequently used for integer values, and especially as the index variable of for loops. In a function with multiple for loops, it is typical for each one to begin for(var i = 0; .... Because var does not scope these variables to the loop body, each of these loops is (harmlessly) re-declaring and re-initializing the same variable.

我无法理解这段话的意思。首先,我假设以下内容不适用于不迭代的第二个循环,因为 i 将是函数范围的:

(function foo() {
    for (let i = 0; i < 2; i++) {
        console.log(i);
    }
    for (let i = 0; i < 2; i++) {
        console.log(i);
    }
})();

但它打印

0
1
0
1

然后我假设这会打印 0 0 1 1 0 1,但事实并非如此:

(function foo() {
    for (var i = 0; i < 2; i++) {
        console.log(i);
        for (var i = 0; i < 2; i++) {
            console.log(i);
        }
    }
})();

谁能帮我理解

是什么意思

in a function of multiple for loops, var can be used harmlessly in each loop

它与 let 有何不同?

对我来说,它看起来恰恰相反(这也很令人困惑),其中 let 可以在具有多个循环的函数中无害地使用:

(function foo() {
    for (let i = 0; i < 2; i++) {
        console.log(i);
        for (let i = 0; i < 2; i++) {
            console.log(i);
        }
    }
})();

打印:

0
0
1
1
0
1

let变量禁止在re-declared同一个作用域,如下:

let foo = 10;
let foo = 20;

var 变量可以是:

var foo = 10;
var foo = 20;
console.log('ok');

在您的第一个片段中,在 for 循环的 header 中用 let 声明的变量仅存在于循环内;它们是块范围的,而不是外部块或函数的范围:

(function foo() {
    for (let i = 0; i < 2; i++) {
        // console.log(i);
    }
    for (let i = 0; i < 2; i++) {
        // console.log(i);
    }
    // doesn't exist out here:
    console.log(i);
})();

上面的 let is 在 两个不同的 范围内创建了 is,这就是为什么它没有被禁止的原因。同样:

(function foo() {
    {
        let i = 10;
    }
    {
        let i = 20;
    }
    console.log('OK up until here');
    // doesn't exist out here:
    console.log(i);
})();

相比之下,

vars 具有函数作用域,而不是块作用域 - 对于循环的 var 版本,因为只有一个函数,this:

(function foo() {
    for (var i = 0; i < 2; i++) {
        console.log(i);
        for (var i = 0; i < 2; i++) {
            console.log(i);
        }
    }
})();

等同于

(function foo() {
    var i; // the `i` variable exists at this level
    for (i = 0; i < 2; i++) {
        console.log(i);
        for (i = 0; i < 2; i++) {
            console.log(i);
        }
    }
})();

Then I assumed this would have printed 0 0 1 1 0 1, which is also not the case:

i 在每个循环开始时被初始化为零。

第一个循环在函数的开头开始一次。

第二个循环在记录 i 之后开始,在外循环的每次迭代中。

(function foo() {
    for (var i = 0; i < 2; i++) {
        console.log(i);
        for (var i = 0; i < 2; i++) {
            console.log(i);
        }
    }
})();
  • 外循环初始化:0赋值给i
  • 0 被记录
  • 内循环初始化:0赋值给i
  • 0 被记录
  • 内部循环将 i 递增到 1 并重新开始
  • 内循环:1 被记录
  • 内部循环将 i 递增到 2 并中断,因为 i < 2 不再满足
  • 外循环将 i 递增到 3 并中断,因为 i < 2 不再满足

所以你得到 0 0 1 记录。

文章的大概意思

in a function of multiple for loops, var can be used harmlessly in each loop

如果两个循环都在函数的相同级别,它就可以工作,例如

for (...) {
}
for (...) {
}

如果两个循环使用相同的变量,绝对不会使用嵌套循环,因为只有一个 i 变量,而不是一个用于每个循环。

where let can be used harmlessly in functions with multiple loops:

对于嵌套循环,是的,因为使用 let 声明的变量对于每个循环都是唯一的,而不是在整个包含函数中共享。