for..of循环

伴随着我们熟知的JavaScriptforfor..in循环,ES6增加了一个for..of循环,它循环遍历一组由一个 迭代器(iterator) 产生的值。

你使用for..of循环遍历的值必须是一个 可迭代对象(iterable),或者它必须是一个可以被强制转换/封箱(参见本系列的 类型与文法)为一个可迭代对象的值。一个可迭代对象只不过是一个可以生成迭代器的对象,然后由循环使用这个迭代器。

让我们比较for..offor..in来展示它们的区别:

var a = ["a","b","c","d","e"];

for (var idx in a) {
    console.log( idx );
}
// 0 1 2 3 4

for (var val of a) {
    console.log( val );
}
// "a" "b" "c" "d" "e"

如你所见,for..in循环遍历数组a中的键/索引,而for.of循环遍历a中的值。

这是前面代码段中for..of的前ES6版本:

var a = ["a","b","c","d","e"],
    k = Object.keys( a );

for (var val, i = 0; i < k.length; i++) {
    val = a[ k[i] ];
    console.log( val );
}
// "a" "b" "c" "d" "e"

而这是一个ES6版本的非for..of等价物,它同时展示了手动迭代一个迭代器(见第三章的“迭代器”):

var a = ["a","b","c","d","e"];

for (var val, ret, it = a[Symbol.iterator]();
    (ret = it.next()) && !ret.done;
) {
    val = ret.value;
    console.log( val );
}
// "a" "b" "c" "d" "e"

在幕后,for..of循环向可迭代对象要来一个迭代器(使用内建的Symbol.iterator;参见第七章的“通用Symbols”),然后反复调用这个迭代器并将它产生的值赋值给循环迭代的变量。

在JavaScript标准的内建值中,默认为可迭代对象的(或提供可迭代能力的)有:

  • 数组
  • 字符串
  • Generators(见第三章)
  • 集合/类型化数组(见第五章)

警告: 普通对象默认是不适用于for..of循环的。因为他们没有默认的迭代器,这是有意为之的,不是一个错误。但是,我们不会进一步探究这其中微妙的原因。在第三章的“迭代器”中,我们将看到如何为我们自己的对象定义迭代器,这允许for..of遍历任何对象来得到我们定义的一组值。

这是如何遍历一个基本类型的字符串中的字符:

for (var c of "hello") {
    console.log( c );
}
// "h" "e" "l" "l" "o"

基本类型字符串"hello"被强制转换/封箱为等价的String对象包装器,它是默认就是一个可迭代对象。

for (XYZ of ABC)..中,XYZ子句既可以是一个赋值表达式也可以是一个声明,这与forfor..in中相同的子句一模一样。所以你可以做这样的事情:

var o = {};

for (o.a of [1,2,3]) {
    console.log( o.a );
}
// 1 2 3

for ({x: o.a} of [ {x: 1}, {x: 2}, {x: 3} ]) {
  console.log( o.a );
}
// 1 2 3

与其他的循环一样,使用breakcontinuereturn(如果是在一个函数中),以及抛出异常,for..of循环可以被提前终止。在任何这些情况下,迭代器的return(..)函数(如果存在的话)都会被自动调用,以便让迭代器进行必要的清理工作。

注意: 可迭代对象与迭代器的完整内容参见第三章的“迭代器”。

results matching ""

    No results matching ""