Iterator 概念
遍历器本质上就是一个指针对象
- 只有布置了遍历器接口,才可遍历。遍历器接口是
[Symbol.iterator]
Iterator 作用
- 为各种数据结构提供一个统一的访问接口
- 使得数据结构的成员能够按照某种次序排序
- 为
for of
提供接口
Iterator 遍历过程
- 创建一个指针对象,指向当前数据结构的起始位置
- 第一次调用指针对象的
next
方法,可以将指针指向数据结构的第一个成员。返回数据结构的当前成员,具体就是一个包含value
和done
的对象。 - 不断调用指针对象的
next
方法,直到它指向数据结构的结束位置
默认 Iterator 接口
注意,对象没有Iterator接口
- 原生具备 Iterator 接口的数据结构如下
- Array
- Set,类似数组,但是成员的值是唯一的
- Map,类似对象,但是"键"的范围不限于字符串,各种类型的值都可以当作键
- String
- TypedArray
- 函数的 arguments 对象
- NodeList 对象(类数组对象)
- object 不具备原生
Iterator
接口,需要在[Symbol.iterator]
上布置。生成的每项形式为[key,val]
// 为一个类数组对象布置 Iterator 接口
let obj = {
0:'y',
1: 'f',
length: 2,
[Symbol.iterator]() {
const self = this;
let index = 0;
return {
next() {
if (index < self.length) {
return {
value: [index,self[index++]],
done: false
};
} else {
return { value: undefined, done: true };
}
}
};
}
};
// 布置到 Object 上
Object.prototype[Symbol.iterator] = function () {
}
通过遍历器实现指针结构的例子
// 指针结构
// 数据结构
function Obj(value) {
this.value =value;
this.next = null;
}
// 布置遍历接口
Obj.prototype[Symbol.iterator] = function () {
var iterator = { next: next };
var current = this;
function next() {
if (current) {
val value = current.value;
current = current.next;
return { done: false, value: value }
} else {
return { done: true }
}
}
return iterator;
}
var one = new Obj(1);
var two = new Obj(2);
var three = new Obj(3);
one.next = two;
two.next = three;
for (var i of one) {
console.log(i);
}
生成 Iterator 方式
var arr = [1,2,3];
var iterator = arr[Symbol.iterator]();
默认调用Iterator
接口的场合
- 解构赋值
- 对数组和
Set
解构进行解构赋值时
- 扩展运算符
-
...
使用扩展运算符
yield*
- 其他场合
for of
Array.from()
Map()
Set()
WeakMap()
WeakSet()
Promise.all()
Promise.race()
// 解构赋值
let set = new Set().add('a').add('b').add('c');
let [x,y] = set;
字符串的 Iterator
接口
// 使用字符串原生的遍历器接口
var str = 'hi';
var iterator = str[Symbol.iterator]();
iterator.next() // { value: "h", done: false }
iterator.next() // { value: "i", done: false }
iterator.next() // { value: undefined, done: true }
遍历器对象的return(),throw()
在
for of
中使用break
或者continue
提前退出,会调用return
方法
//遍历器,必须返回一个包含next方法的对象
// 可选的返回一个包含了throw方法和return方法的对象
function ite() {
return {
next() {
return {done: false}
},
return() {
file.close();
return { done: true }
}
}
}
// throw 方法不常用
for of
循环
数组
// for in 获取的是键名,包含了数组的索引和属性,甚至原型上的属性
var arr = [7,9,0];
arr.foo = 'bar';
for (let i in arr) {
console.log(i); // '0','1','2','foo'
}
// for of 获取的是数组每项的值
for (let i of arr) {
console.log(i); // '7','9','0'
}
Set 和 Map 解构
计算生成的数据结构
数组,Set,Map部署了下面三个方法,这些方法都返回遍历器对象
entries()
keys()
values()
类似数组的对象
并不是所有类似数组的对象都有 Iterator 接口,可以使用
Array.from
将其转化为数组,再使用for of
方法
对象
普通对象,不能直接使用
for of
,会报错。解决方法:
- 使用
Object.keys()
生成一个由对象属性值组成的数组,再使用for of
- 另一个方法使用
Generator
将对象包装一下 - 可以在对象实例上直接布置
[Symbol.iterator]
,也可以在对象原型链上布置[Symbol.iterator]
。部署类数组对象的[Symbol.iterator]
和普通对象的[Symbol.iterator]
方法不同
// 使用 Generator 将对象包装一下
function* entries(obj) {
// 使用的是Object.keys而不是for in 循环
for (let key of Object.keys(obj)) {
yield [key, obj[key]];
}
}
for (let [key, value] of entries(obj)) {
console.log(key, '->', value);
}
网友评论