for...of
for...of
for...of语句
在可迭代对象(包括Array
,Map
,Set
,String
,TypedArray
,arguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句。
语法
for (variable of iterable) {
statement
}
variable
在每次迭代中,将不同属性的值分配给变量。iterable
可枚举其枚举属性的对象。
示例
迭代Array
let iterable = [10, 20, 30];
for (let value of iterable) {
value += 1;
console.log(value
}
// 11
// 21
// 31
如果你不想修改语句块中的变量 , 也可以使用const
代替let
。
let iterable = [10, 20, 30];
for (const value of iterable) {
console.log(value
}
// 10
// 20
// 30
迭代String
let iterable = 'boo';
for (let value of iterable) {
console.log(value
}
// "b"
// "o"
// "o"
迭代 TypedArray
let iterable = new Uint8Array([0x00, 0xff]
for (let value of iterable) {
console.log(value
}
// 0
// 255
迭代Map
let iterable = new Map([['a', 1], ['b', 2], ['c', 3]]
for (let entry of iterable) {
console.log(entry
}
// ['a', 1]
// ['b', 2]
// ['c', 3]
for (let [key, value] of iterable) {
console.log(value
}
// 1
// 2
// 3
迭代 Set
let iterable = new Set([1, 1, 2, 2, 3, 3]
for (let value of iterable) {
console.log(value
}
// 1
// 2
// 3
迭代 arguments 对象
(function() {
for (let argument of arguments) {
console.log(argument
}
})(1, 2, 3
// 1
// 2
// 3
迭代 DOM 集合
迭代 DOM 元素集合,比如一个NodeList
对象:下面的例子演示给每一个 article 标签内的 p 标签添加一个 "read
" 类:
// Note: This will only work in platforms that have
// implemented NodeList.prototype[Symbol.iterator]
let articleParagraphs = document.querySelectorAll('article > p'
for (let paragraph of articleParagraphs) {
paragraph.classList.add('read'
}
关闭迭代器
对于for...of
的循环,可以由break
, continue[4]
, throw
或return[5]
终止。在这些情况下,迭代器关闭。
function* foo(){
yield 1;
yield 2;
yield 3;
};
for (let o of foo()) {
console.log(o
break; // closes iterator, triggers return
}
迭代生成器
你还可以迭代一个生成器:
function* fibonacci() { // a generator function
let [prev, curr] = [0, 1];
while (true) {
[prev, curr] = [curr, prev + curr];
yield curr;
}
}
for (let n of fibonacci()) {
console.log(n
// truncate the sequence at 1000
if (n >= 1000) {
break;
}
}
不要重用生成器
生成器不应该重用,即使for...of
循环的提前终止,例如通过break
关键字。在退出循环后,生成器关闭,并尝试再次迭代,不会产生任何进一步的结果。
var gen = (function *(){
yield 1;
yield 2;
yield 3;
})(
for (let o of gen) {
console.log(o
break; // Closes iterator
}
// The generator should not be re-used, the following does not make sense!
for (let o of gen) {
console.log(o // Never called.
}
迭代其他可迭代对象
你还可以迭代显式实现可迭代协议的对象:
var iterable = {
[Symbol.iterator]() {
return {
i: 0,
next() {
if (this.i < 3) {
return { value: this.i++, done: false };
}
return { value: undefined, done: true };
}
};
}
};
for (var value of iterable) {
console.log(value
}
// 0
// 1
// 2
for...of与for...in的区别
无论是for...in
还是for...of
语句都是迭代一些东西。它们之间的主要区别在于它们的迭代方式。
for...in
语句以原始插入顺序迭代对象的可枚举属性。
for...of
语句遍历可迭代对象定义要迭代的数据。
以下示例显示了与Array
一起使用时,for...of
循环和for...in
循环之间的区别。
Object.prototype.objCustom = function() {};
Array.prototype.arrCustom = function() {};
let iterable = [3, 5, 7];
iterable.foo = 'hello';
for (let i in iterable) {
console.log(i // logs 0, 1, 2, "foo", "arrCustom", "objCustom"
}
for (let i in iterable) {
if (iterable.hasOwnProperty(i)) {
console.log(i // logs 0, 1, 2, "foo"
}
}
for (let i of iterable) {
console.log(i // logs 3, 5, 7
}
Object.prototype.objCustom = function() {};
Array.prototype.arrCustom = function() {};
let iterable = [3, 5, 7];
iterable.foo = 'hello';
每个对象将继承objCustom
属性,并且作为Array
的每个对象将继承arrCustom
属性,因为将这些属性添加到Object.prototype
和Array.prototype
。由于继承和原型链,对象iterable
继承属性objCustom
和arrCustom
。
for (let i in iterable) {
console.log(i // logs 0, 1, 2, "foo", "arrCustom", "objCustom"
}
此循环仅以原始插入顺序记录iterable
对象的可枚举属性。它不记录数组元素
3
, 5
, 7
或hello
,因为这些不是
枚举属性。但是它记录了数组索引
以及arrCustom
和objCustom
。如果你不知道为什么这些属性被迭代,array iteration and for...in
中有更多解释。
for (let i in iterable) {
if (iterable.hasOwnProperty(i)) {
console.log(i // logs 0, 1, 2, "foo"
}
}
这个循环类似于第一个,但是它使用hasOwnProperty()
来检查,如果找到的枚举属性是对象自己的(不是继承的
)。如果是,该属性被记录。记录的属性是0
, 1
, 2
和foo
,因为它们是自身的属性(不是继承的
)。属性arrCustom
和objCustom
不会被记录,因为它们是继承的
。
for (let i of iterable) {
console.log(i // logs 3, 5, 7
}
该循环迭代并记录iterable
作为可迭代对象定义的迭代值,这些是数组元素 3
, 5
, 7
,而不是任何对象的属性
。
规范
Specification | Status | Comment |
---|---|---|
ECMAScript 2015 (6th Edition, ECMA-262)The definition of 'for...of statement' in that specification. | Standard | Initial definition. |
ECMAScript Latest Draft (ECMA-262)The definition of 'for...of statement' in that specification. | Living Standard | |
浏览器兼容性
Feature | Chrome | Firefox (Gecko) | Edge | Opera | Safari |
---|---|---|---|---|---|
Basic support | 38 1 51 3 | 13 (13) 2 | 12 | 25 | 7.1 |
Closing iterators | (Yes) | 53 (53) | (Yes) | (Yes) | (Yes) |
Feature | Android | Chrome for Android | Edge | Firefox Mobile (Gecko) | IE Mobile | Opera Mobile | Safari Mobile |
---|---|---|---|---|---|---|---|
Basic support | 5.1 | 38 1 | (Yes) | 13.0 (13) 2 | No support | ? | 8 |
Closing iterators | (Yes) | (Yes) | (Yes) | 53.0 (53) | (Yes) | (Yes) | (Yes) |