概念
iterator
是接口的一种机制,为各种不同类型的数据提供统一的访问机制,使不同数据结构可以按照某种次序排列。iterator
接口主要供 ES6中新增的for..of
循环消费~
内置iterator接口
字符串 数组 映射 集合 arguments对象 NodeList等DOM集合类型
let str = 'abc';
let arr = ['a', 'b', 'c'];
let map = new Map()
.set('a', 1)
.set('b', 2)
.set('c', 3);
let set = new Set()
.add('a')
.add('b')
.add('c');
let els = document.querySelectorAll('div');
// 调用这个工厂函数会生成一个迭代器
console.log(str[Symbol.iterator]()); // StringIterator {}
console.log(arr[Symbol.iterator]()); // ArrayIterator {}
console.log(map[Symbol.iterator]()); // MapIterator {}
console.log(set[Symbol.iterator]()); // SetIterator {}
console.log(els[Symbol.iterator]()); // ArrayIterator {}
接收可迭代对象
- for-of 循环
- 数组解构
- 扩展操作符
- Array.from()
- 创建集合
- 创建映射
- Promise.all()接收由期约组成的可迭代对象
- Promise.race()接收由期约组成的可迭代对象
- yield*操作符,在生成器中使用
执行顺序
- 创建一个指针对象,指向当前数据的起始位置。
- 调用指针的next方法,将指针指向数据的第一个成员。
- 不断调用next方法,直到它指向数据结构的结束位置。
手写Iterator
let arr = iterator(['a','b','c'])
function iterator(arr){
let index = 0;
return {
next(){
return index < arr.length ? {
value:arr[index++],
done:false
}:{
next:undefined,
done:true
}
}
}
}
console.log(arr.next()); // {value: "a", done: false}
console.log(arr.next()); // {value: "b", done: false}
console.log(arr.next()); // {value: "c", done: false}
console.log(arr.next()); // {next: undefined, done: true}
原生iterator
原生js中也有好多默认实现了iterator接口。比如:Array、arguments、Set、Map、String、NodeList都通过了默认iterator接口
let arr = ['banana', 'apple', 'orange']
// 得到arr中iterator 接口
let arrNext = arr[Symbol.iterator]()
console.log(arrNext.next()); // {value: "banana", done: false}
console.log(arrNext.next()); // {value: "apple", done: false}
console.log(arrNext.next()); // {value: "orange", done: false}
console.log(arrNext.next()); // {value: undefined, done: true}
let str = 'bac'
let iterStr = str[Symbol.iterator]();
iterStr.next(); // {value: "b", done: false}
iterStr.next(); // {value: "a", done: false}
iterStr.next(); // {value: "c", done: false}
iterStr.next(); // {value: undefined, done: true}
for.of
上面我们说了,只有提供了
iterator
接口的才能使用for.of
循环。
// 当然如果不信的话 我们可以循环object测试一下
let obj = {
name: "前端伪大叔",
age: 19,
like: 'web'
}
for (k of obj) {
console.log(k); // iterator.html:59 Uncaught TypeError: obj is not iterableat iterator.html:59
}
// 当然也可以使用下面方法部署 iterator接口
for (k of Reflect.ownKeys(obj)) {
console.log(`${k}:${obj[k]}`);
// 但是如果你继续在查找原型上查找的话 还是会找到iterator属性~~~~
console.log(Reflect.ownKeys(obj).__proto__); // Symbol(Symbol.iterator): ƒ values()
}
for(k of Object.keys(obj)){
console.log(`${k}:${obj[k]}`);
console.log(Object.keys(obj).__proto__); // Symbol(Symbol.iterator): ƒ values()
}
总结
iterator接口是为了解决ES5的for..in 循环遗留下不能循环value的bug,如果需要使用for..of遍历的话可以加上iterator接口就可以实现遍历