for...of

for...of

for...of语句在可迭代对象(包括ArrayMapSetStringTypedArray,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的循环,可以由breakcontinue[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.prototypeArray.prototype。由于继承和原型链,对象iterable继承属性objCustomarrCustom

for (let i in iterable) { console.log(i // logs 0, 1, 2, "foo", "arrCustom", "objCustom" }

此循环仅以原始插入顺序记录iterable 对象的可枚举属性。它不记录数组元素357 或hello,因为这些不是枚举属性。但是它记录了数组索引以及arrCustomobjCustom。如果你不知道为什么这些属性被迭代,array iteration and for...in中有更多解释。

for (let i in iterable) { if (iterable.hasOwnProperty(i)) { console.log(i // logs 0, 1, 2, "foo"  } }

这个循环类似于第一个,但是它使用hasOwnProperty()来检查,如果找到的枚举属性是对象自己的(不是继承的)。如果是,该属性被记录。记录的属性是012foo,因为它们是自身的属性(不是继承的)。属性arrCustomobjCustom不会被记录,因为它们是继承的

for (let i of iterable) { console.log(i // logs 3, 5, 7 }

该循环迭代并记录iterable作为可迭代对象定义的迭代值,这些是数组元素 357,而不是任何对象的属性

规范

SpecificationStatusComment
ECMAScript 2015 (6th Edition, ECMA-262)The definition of 'for...of statement' in that specification.StandardInitial definition.
ECMAScript Latest Draft (ECMA-262)The definition of 'for...of statement' in that specification.Living Standard

浏览器兼容性

FeatureChromeFirefox (Gecko)EdgeOperaSafari
Basic support38 1 51 313 (13) 212257.1
Closing iterators(Yes)53 (53)(Yes)(Yes)(Yes)

FeatureAndroidChrome for AndroidEdgeFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Basic support5.138 1(Yes)13.0 (13) 2No support?8
Closing iterators(Yes)(Yes)(Yes)53.0 (53)(Yes)(Yes)(Yes)