迭代器与生成器

Iterators and Generators

可迭代对象(Iterables)

在对象有着Symbol.iterator属性时,其就被认为是可迭代的。一些内建类型,比如ArrayMapSetStringInt32ArrayUint32Array等,都已经有着其已实现的Symbol.iterator属性。对象上的Symbol.iterator函数,赋值返回要迭代的值的清单(Symbol.iterator function on an object is responsible for returning the list of values to iterate on)。

for..of语句

for..of对可迭代对象进行循环,调用对象上的Symbol.iterator属性。下面是一个在数组上的简单for..of循环:

let someArray = [1, "string", false];

for (let entry of someArray){
    console.log(entry); // 1, "string", false
}

for..offor..in语句

for..offor..in语句都是对清单进行迭代;但所迭代的值却是不同的,for..in返回的是所迭代对象的 的清单,而for..of则是返回的所迭代对象数值属性的 的清单(Both for..of and for..in statements iterate over lists; the values iterated on are differenct though, for..in returns a list of keys on the object being iterated, whereas for..of returns a list of values of the numeric properties of the object being interatd)。

let list = [4, 5, 6];

for (let i in list) {
    console.log(i); // "0", "1", "2"
}

for (let i of list) {
    console.log(i); // "4", "5", "6"
}

另一个区别就是for..in在任何对象上均可执行;它提供了一种探测对象上属性的方法。而for..of则主要关注的是可迭代对象的值。诸如MapSet等实现了Symbol.iterator属性的内建对象,才允许对存储值的访问(Built-in objects like Map and Set implement Symbol.iterator property allowing access to stored values)。

let pets = new Set(["Cat", "Dog", "Hamster"]);

pets["species"] = "mammals";

for (let pet in pets) {
    console.log(pet); // "species"
}

for (let pet of pets) {
    console.log(pet); // "Cat", "Dog", "Hamster"
}

关于代码生成(Code generation)

目标代码为ES5及ES3

在生成目标代码为ES5或ES3时,只允许在Array类型上使用迭代器。就算非数组值实现了Symbol.iterator属性, 在它们上使用for..of循环都是错误的。

编译器将为for..of循环生成一个简单的for循环,例如:

let numbers = [1, 2, 3];

for (let num of numbers) {
    console.log(num);
}

将生成如下代码:

var numbers = [1, 2, 3];

for (var _i = 0; _i < numbers.length; _i++) {
    var num = numbers[_i];
    console.log(_i);
}

目标代码为ECMAScript2015或更高版本时

在以兼容ECMAScript2015引擎为目标时,编译器将生成for..of循环,从而以引擎中的内建迭代器实现为目标。

Last change: 2023-03-28, commit: 4e70b88