Open brunoyang opened 8 years ago
JavaScript 的历史上,先有两种集合,Array 和 Object,ES6 中新加了两种集合,Map 和 Set。遍历 Array 可以用 for 循环或 forEach 等 ES5 中提供的遍历方法,Object 使用 for...in,Map 和 Set 使用 for...of。可以预见,如果不添加一个统一的遍历接口,数据结构改变就需要不同的遍历方法,势必会越来越混乱。所以,ES6 中添加了迭代器(Iterator)这一机制,为不同的数据结构提供统一的访问接口。
Array
Object
Map
Set
forEach
for...in
for...of
所谓迭代器,就是一种封装,封装了获取集合中某个值的操作,而屏蔽了『如何拿到某个值』的细节。举个例子,如果想获取对象和数组的第一个值,数组的取值方法是 arr[0], 对象的取值方法是 for (const v in obj) obj[v]。为了屏蔽差异,我们需要设计一种通用的方法。一种做法就是往这些集合上增加个方法,该方法可以拿到集合中的值,取值时只需要调用这个方法就可以了。
for (const v in obj) obj[v]
ES6 中数组部署了迭代器,我们来看看如何使用迭代器遍历数组:
const arr = [1,2,3] const iterator = arr[Symbol.iterator]() iterator.next() // { value: 1, done: false } iterator.next() // { value: 2, done: false } iterator.next() // { value: 3, done: false } iterator.next() // { value: undefined, done: true } iterator.next() // { value: undefined, done: true }
上面短短几行中,有几点是需要注意的:
{ value: undefined, done: true }
一遍一遍地写 .next() 相当低效,所以 ES6 引入了 for...of 帮我们自动遍历。for...of 会自动调用迭代器接口,类似这样:
const arr = [1,2,3] for (const v of arr) { console.log(v) // 1, 2, 3 }
四大集合,Array、Set、Map 都有迭代器接口,独独少了 Object,据说是为了以后考虑。不过虽说官方没有默认提供,我们可以手动添加,自己实现个迭代器:
const foo = { a: 1, b: 2, c: 3, } Object.defineProperty(foo, Symbol.iterator, { configurable: false, enumerable: false, writable: false, get: () => { let index = -1 const values = Object.entries(foo) const len = values.length return () => ({ next: () => { index++ return { value: values[index] ? values[index][1] : undefined, done: index >= len ? true : false, } } }) } }) for (const v of foo) { console.log(v) // 1, 2, 3 }
done, for...of 识别出了我们自定义的迭代器!
{ value: xx, done: false } 这样的对象感觉很眼熟... 我们来对比一下数组和 generator function:
{ value: xx, done: false }
const arr = [1,2,3] const iterator = arr[Symbol.iterator]() iterator.next() // { value: 1, done: false } // ---------------------- function * iterFunc () { let i = 1 while (true) { yield i++ } } const gen = iterFunc() gen.next() // { value: 1, done: false }
简直一毛一样。
而且,generator 函数还可以用来部署迭代器
function* makeIterator(obj){ var nextIndex = 0; var values = Object.entries(obj) while(nextIndex < values.length){ yield values[nextIndex++][1]; } } var gen = makeIterator({ a: 1, b: 2, }); for (const v of gen) { console.log(v); // 1, 2 }
其实 ES6 中迭代器无处不在,随便列举几个
rest 参数:
function rest (...args) { for (const v of args) { console.log(args) } }
解构赋值:
const [a, b] = 'a.b'.split('.') const [c, d] = 'a.b.c'.split('.') // c: 'a', d: ['b', 'c']
还可以对类数组比如字符串等操作:
[...'abc'] // 'a', 'b', 'c'
已撸
JavaScript 的历史上,先有两种集合,
Array
和Object
,ES6 中新加了两种集合,Map
和Set
。遍历Array
可以用 for 循环或forEach
等 ES5 中提供的遍历方法,Object
使用for...in
,Map
和Set
使用for...of
。可以预见,如果不添加一个统一的遍历接口,数据结构改变就需要不同的遍历方法,势必会越来越混乱。所以,ES6 中添加了迭代器(Iterator)这一机制,为不同的数据结构提供统一的访问接口。什么是迭代器
所谓迭代器,就是一种封装,封装了获取集合中某个值的操作,而屏蔽了『如何拿到某个值』的细节。举个例子,如果想获取对象和数组的第一个值,数组的取值方法是 arr[0], 对象的取值方法是
for (const v in obj) obj[v]
。为了屏蔽差异,我们需要设计一种通用的方法。一种做法就是往这些集合上增加个方法,该方法可以拿到集合中的值,取值时只需要调用这个方法就可以了。使用迭代器
ES6 中数组部署了迭代器,我们来看看如何使用迭代器遍历数组:
上面短短几行中,有几点是需要注意的:
{ value: undefined, done: true }
。迭代器与
for...of
一遍一遍地写 .next() 相当低效,所以 ES6 引入了
for...of
帮我们自动遍历。for...of
会自动调用迭代器接口,类似这样:自己实现个迭代器
四大集合,
Array
、Set
、Map
都有迭代器接口,独独少了Object
,据说是为了以后考虑。不过虽说官方没有默认提供,我们可以手动添加,自己实现个迭代器:done,
for...of
识别出了我们自定义的迭代器!迭代器与 generator
{ value: xx, done: false }
这样的对象感觉很眼熟... 我们来对比一下数组和 generator function:简直一毛一样。
而且,generator 函数还可以用来部署迭代器
迭代器的其他用途
其实 ES6 中迭代器无处不在,随便列举几个
rest 参数:
解构赋值:
还可以对类数组比如字符串等操作: