ES6学习笔记18:Iterator 和 for...of

Iterator 定义

在JavaScript中,表示集合的数据结构只要是:ArrayObject,在ES6中添加了MapSet。Iterator (遍历器)为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署Iterator接口,就可以进行遍历操作。(即:依次处理这个数据结构的所有成员)

Iterator 的作用
  • 为各种数据结构提供统一、比娜姐的访问接口。
  • 是的数据结构的成员按照某种次序排列
  • Iterator接口主要提供与for...of使用
Iterator 的遍历过程
  1. 创建一个指针对象,指向当前数据结构的起始位置
  2. 调用指针对象的next方法,将指针指向数据结构的下一个成员
  3. 不断调用指针对象的next方法,知道它指向数据结构的结束位置

指针的next方法返回一个对象,表示当前数据成员的信息。这个对象有value(返回当前位置的成员)和done(表示遍历是否解释)两个属性。对于Iterator(遍历器)来说,done:falsevalue:undefined属性都是可以省略的。遍历器与它所遍历的数据结构是分开的,完全可以写出没有对应数据结构的遍历对象。

默认Iterator接口

当使用for...of循环遍历某种数据结构时,这个循环自动去寻找Iterator接口。

ES6中,默认的Iterator接口部署在数据结构的Symbol.iterator属性,或者具有Symbol.iterator属性,就认为是“可遍历的”。

原生具有Iterator接口的数据结构
  • Array
  • Map
  • Set
  • String
  • TypedArray
  • 函数的arguments对象
  • NodeList对象
对象为什么没有Iterator接口

对象(Object)没有Iterator接口,是因为不确定对象属性的遍历顺序,需要手动指定。本质上,遍历器是一种线性处理,对于任何非线性的数据结构,部署遍历器接口,相当于是将非线性的数据结构转换为线性数据结构。

如果一个对象可以被for...of循环调用,就必须在Symbol.iterator的属性上部署遍历器的生成方法或者在原型链上具有也可以。

如果Symbol.iterator方法对应的不是遍历器生成函数,解释引擎将会报错。

调用Iterator接口的具体应用

解构赋值

对数组和Set结构进行解构赋值时,默认会调用Symbol.iterator方法

const set = new Set().add('a').add('b').add('c');
const [x,y] = set;
console.log(x); // 'a'
console.log(y); // 'b'

const [first, ...rest] = set;
console.log(first); // 'a'
console.log(rest);  // ['b','c']
扩展运算符

扩展运算符(...)也会调用默认的Iterator接口

const str = 'abc';
console.log([...str]); // ['a','b','c']
yield*

yield*后面跟着一个可遍历的结构,他会调用这个结构的遍历接口。

const generator = function*(){
  yield 1;
  yield* [2,3,4];
};
const iterator = generator();
console.log(iterator.next()); // {value: 1, done: false}
console.log(iterator.next()); // {value: 2, done: false}
其他
  • for...in
  • Array.from()
  • Map()Set()WeakMap()WeakSet()
  • Promise.all()
  • Promise.race()

字符串的Iterator接口

字符串是一个类似数组的对象,具有原生Iterator接口

const str = 'abc';
console.log(typeof str[Symbol.iterator]); // 'function'
const iterator = str[Symbol.iterator];
console.log(iterator.next()); // {value: 'a', done: false}
console.log(iterator.next()); // {value: 'b', done: false}

Iterator(遍历器)对象的return()、throw()

return() 使用场景

  • for...of循环提前退出(出错或者有break语句),此时Iterator(遍历器)对象就会调用return()方法.
  • 如果一个对象在完成遍历前,需要清理或者释放资源,就可以部署return方法

方法return()方法必须返回的是一个对象,这个Generator规格决定的

throw() 使用场景

方法throw()主要是配合Generator函数使用。

for…in 和 for…of 的比较

  • 对于普通对象,for...of不能直接使用,会报错。for...in循环可以用来遍历键名
  1. 此时可以使用Object.keys方法将对象的键名生成一个数据,然后遍历这个数组

  2. 使用Generator 函数将这个普通对象重新包装一下

function* entries(obj){
  for (let key of Object.keys(obj)){
    yield [key, obj[key]];
  }
}

for (let [key,value] of entries(obj)){
  console.log(key + '->' + value)
}
  • 数组的键名是数字,但是for...in循环是以字符串作为键名。

  • for...in循环会手动添加其他键,甚至包括原型链上的键

  • 某些情况下,for...in循环会以任意顺序遍历键名

  • for...of不同于forEach,可以与breakcontinuereturn配合使用

  • for...of提供了便利所有数据结构的统一接口操作

备注:本文是自己学习阮一峰老师的《ECMAScript 6 入门》所做的笔记,大部分例子来源于此书。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值