提及迭代器, 那就要先了解迭代模式前端
迭代模式: 提供一种方法能够顺序得到聚合对象中的各个元素, 是一种最简单,后端
也是最多见的设计模式,它可让用户经过特定的接口寻访集合中的每个元素设计模式
而不用了解底层的实现。数组
迭代器 : 依照迭代模式的思想而实现,数据结构
分为内部迭代器和外部迭代器,函数
内部迭代器: 自己是函数, 该函数内部定义好迭代规则,彻底接手整个迭代过程this
外部只须要一次初始调用,如Array.prototype.forEach, Jquery.eachspa
外部迭代器: 自己是函数, 执行返回迭代对象,迭代下一个元素必须显示调用,prototype
调用复杂度增长,但灵活性加强。设计
咱们主要来了解一下外部迭代器:
外部迭代器自己是一个函数, 执行这个函数就至关于启动了这个迭代器,
而后咱们每次迭代须要手动调用next()方法,返回一个对象,
基于此咱们来本身实现一个外部迭代器
const arr = [2,3,4]; function OuterIterator(o) { let curIndex = 0; let next = () => { return { value: o[curIndex], done: o.length === ++curIndex, } }; return { next } } const oIt = OuterIterator(arr); console.log(oIt.next()); console.log(oIt.next()); console.log(oIt.next());
结果:
咱们为何要用外部迭代器呢 ?
想象一个场景, 后端给前端返回一个数组形式的数据, 前端经过for 循环遍历
当业务变更时, 后端传给前端的再也不是数组了, 而是一个对象又
或者是一个Map/Set 结构的数据, 那前端的遍历代码就须要大规模重写。
因此咱们要标准化迭代操做,
解决方案: ES6 引入Iterator, 部署在NodeLlist, argument, Array, Set, Map , 字符串
等数据上的Symbol.iterator属性 , 使得这些数据是可迭代的, 并可进行
for...of , ... , Array.from等操做。
这里插播一个内容Symbol: js 第七种 基本数据结构
特色: 惟一, 可做为对象属性, 有静态方法Symbol.iterator
Symbol若是传入的是对象的话,会隐式调用对象的toString() 方法,好比:
let os = Symbol({'name': 'liu'}); console.log(os); let os2 = Symbol({'name': 'liu', toString() { return "我最帅" }}); console.log(os2);
咱们重写了对象的toString方法, 结果:
回到主题, 原生有iterator接口的只有NodeLlist, argument, Array, Set, Map , 字符串等数据
对象上是没有iterator的, 因此它不能被迭代, 也不能进行for...of , ... , Array.from等操做
那咱们要迭代对象怎么办呢 ?
没错, 就是给它加上咱们本身按照ES6规范写外部迭代器:
const obj = {
0: 'liu',
1: '18',
2: 'man',
}; console.log([...obj]);
直接用...操做符报错, obj 不可迭代
const obj = { 0: 'liu', 1: '18', 2: 'man', length: 4, [Symbol.iterator] : function () { let curIndex = 0; let next = () => { return { value: this[curIndex], done: this.length === ++curIndex, } }; return { next } } }; console.log([...obj]);
结果:
obj必须是类数组, 就是属性是数字 , 且有length属性 才能这样写。
咱们下一篇来讨论generator生成器, 它能够生成一个迭代对象。