Open ChuChencheng opened 4 years ago
遍历器(Iterator),一种为不同数据结构提供统一的访问机制的接口。
作用:
for...of
TypeScript 定义:
interface Iterable<T> { [Symbol.iterator](): Iterator<T>; } interface Iterator<T, TReturn = any, TNext = undefined> { // NOTE: 'next' is defined using a tuple to ensure we report the correct assignability errors in all places. next(...args: [] | [TNext]): IteratorResult<T, TReturn>; return?(value?: TReturn): IteratorResult<T, TReturn>; throw?(e?: any): IteratorResult<T, TReturn>; } type IteratorResult<T, TReturn = any> = IteratorYieldResult<T> | IteratorReturnResult<TReturn>; interface IteratorYieldResult<TYield> { done?: false; value: TYield; } interface IteratorReturnResult<TReturn> { done: true; value: TReturn; }
只要有 [Symbol.iterator] 属性,就认为是“可遍历的”(iterable)
[Symbol.iterator]
在 for...of 循环中,会调用 [Symbol.iterator] ,并执行其返回的 next 函数:
next
const iterable = { [Symbol.iterator] () { let i = 0 return { next () { return { value: i++, done: i > 5 } } } } } for (let i of iterable) { console.log(i) } // 0 1 2 3 4 const iter = iterable[Symbol.iterator]() console.log(iter.next()) // { value: 0, done: false } console.log(iter.next()) // { value: 1, done: false } console.log(iter.next()) // { value: 2, done: false } console.log(iter.next()) // { value: 3, done: false } console.log(iter.next()) // { value: 4, done: false } console.log(iter.next()) // { value: 5, done: true }
原生具备 Iterator 接口的数据结构:
原生数组 Iterator 接口示例:
const arr = [1, 2, 3] const it = arr[Symbol.iterator]() it.next() // { value: 1, done: false } it.next() // { value: 2, done: false } it.next() // { value: 3, done: false } it.next() // { value: undefined, done: true }
Array.from()
Map()
Set()
WeakMap()
WeakSet()
Promise.all()
Promise.race()
Promise.allSettled()
见 Generator 笔记
遍历器对象除了 next ,还可以有 return 与 throw 方法。这两个方法是可选的。
return
throw
return 返回一个对象,在 for...of 循环提前退出(抛出错误或者手动 break )时调用,可作为清理或释放资源用。
break
例如:
function readLinesSync (file) { return { [Symbol.iterator] () { return { next () { return { done: false } }, return () { file.close() return { done: true } } } } } } for (let line of readLinesSync(fileName)) { console.log(line) break } // 或者 for (let line of readLinesSync(fileName)) { console.log(line) throw new Error() }
定义一个逐行读取文件的函数,在遍历完第一行后,如果是 break 或抛出错误了,则执行 return 方法,关闭文件。如果是抛出错误,会在 return 执行之后再抛出(个人未验证)
throw 方法主要配合 Generator 函数使用,见 Generator 笔记
for...in
for...of 循环作为遍历所有数据结构的统一的方法,只要部署了 Symbol.iterator 属性,就可以用 for...of 来遍历,因此,普通的对象不能用 for...of 遍历,只能使用 for...in ,而数组、Map、Set、arguments 对象等,就可以用 for...of 来遍历。
Symbol.iterator
for...in 的缺点:
'0'
'1'
for (let key in [1, 2, 3]) { console.log(typeof key) // string }
const arr = [1, 2, 3] Object.setPrototypeOf(arr, { protoProperty: 666 }) for (let key in arr) { console.log(key) } // 0 1 2 protoProperty
总之 for...in 主要是为遍历对象而设计的,不适用于数组
另外提一下 forEach 这种函数遍历的方式,优点是简洁方便,但缺点也很明显:无法中途跳出循环
forEach
http://es6.ruanyifeng.com/#docs/iterator
概念
遍历器(Iterator),一种为不同数据结构提供统一的访问机制的接口。
作用:
for...of
遍历命令使用规格描述
TypeScript 定义:
只要有
[Symbol.iterator]
属性,就认为是“可遍历的”(iterable)在
for...of
循环中,会调用[Symbol.iterator]
,并执行其返回的next
函数:原生具备 Iterator 接口的数据结构:
原生数组 Iterator 接口示例:
调用 Iterator 接口的场合
for...of
,Array.from()
,Map()
,Set()
,WeakMap()
,WeakSet()
,Promise.all()
,Promise.race()
,Promise.allSettled()
Iterator 接口与 Generator 函数
见 Generator 笔记
return 与 throw
遍历器对象除了
next
,还可以有return
与throw
方法。这两个方法是可选的。return
返回一个对象,在for...of
循环提前退出(抛出错误或者手动break
)时调用,可作为清理或释放资源用。例如:
定义一个逐行读取文件的函数,在遍历完第一行后,如果是
break
或抛出错误了,则执行return
方法,关闭文件。如果是抛出错误,会在return
执行之后再抛出(个人未验证)throw
方法主要配合 Generator 函数使用,见 Generator 笔记for...of
与for...in
for...of
循环作为遍历所有数据结构的统一的方法,只要部署了Symbol.iterator
属性,就可以用for...of
来遍历,因此,普通的对象不能用for...of
遍历,只能使用for...in
,而数组、Map、Set、arguments 对象等,就可以用for...of
来遍历。for...in
的缺点:'0'
,'1'
等作为键名for...in
可能会遍历到原型链上的键for...in
不保证遍历的顺序总之
for...in
主要是为遍历对象而设计的,不适用于数组另外提一下
forEach
这种函数遍历的方式,优点是简洁方便,但缺点也很明显:无法中途跳出循环参考
http://es6.ruanyifeng.com/#docs/iterator