前言
ECMAScript 6中新增了Iterator(迭代器)的概念,它提供了for…of语法对继承了Iterator的对象进行遍历,基本上很多数据集对象都继承了生成迭代器对象的函数,但Object对象却不继承Iterator生成器,即不支持for…of语法来遍历,因此如果我们需要对数据集的遍历使用for…of的方式统一标准,就得让Object对象也能实现Iterator遍历,实现Iterator的方法就是给Object对象定义一个Iterator生成函数,将函数绑定给Symbol(Symbol.iterator)属性,让函数返回一个可遍历对象,可遍历对象的设计参考原生的可遍历对象即可。
功能实现
这里提供两种方式,任意一种都可以实现,最后使用for…of循环测试一下效果,如果Object对象能够成功遍历,说明实现成功了。
方法一:将Object对象封装成数组
思路
由于数组继承了Iterator生成可遍历对象的函数,它支持通过for…of进行遍历,因此我们只需将Object对象拆开并重组成一个Array对象,再对Array对象进行遍历即可。
代码
const obj = {
"name": "luckyboy",
"sex": "male",
"age": 20,
"job": "coder"
}
//给对象定义一个Iterator函数,用于生成可遍历对象
obj[Symbol.iterator] = () => {
//声明一个数组
const arr = [];
//遍历obj对象,将对象中的值插入到数组中
for (let item in obj) {
arr.push(obj[item]);
}
//将数组的Iterator函数生成的可遍历对象返回
return arr[Symbol.iterator]();
}
//obj定义了上面的函数之后,for...of底层便会调用obj的Iterator生成可遍历对象
for (let item of obj) {
console.log(item);
}
方法二:自定义可遍历对象
思路
给Object对象定义Iterator对象生成函数,并且在对象中定义一个next函数,它每次调用的时候都会索引到上次索引的下一个位置,这种写法是参考JavaScript原生可遍历对象的写法。
代码
const obj = {
"name": "luckyboy",
"sex": "male",
"age": 20,
"job": "coder"
}
//给对象定义一个Iterator函数,用于生成可遍历对象
obj[Symbol.iterator] = () => {
//声明一个克隆对象,后续要对对象进行删除操作,但要保护源对象,所以只能对源对象进行克隆
const cloneObj = {};
//遍历obj中的内容,复制到克隆对象中
for (let i in obj) {
cloneObj[i] = obj[i];
}
//函数返回值,返回一个对象,该对象即是可遍历对象
return {
//返回的对象中定义一个next函数,每次调用会索引到下一个值
next: function () {
let value;
/**
* 遍历克隆对象
* 注意:这里一定要用克隆对象,因为有删除操作,要保护源对象的完整性
*/
for (let item in cloneObj) {
//将遍历的值存储,用于返回值
value = cloneObj[item];
//删除当前遍历的键值对
delete cloneObj[item];
break;
}
//值存在,证明遍历还在进行中
if (value) {
return {
value,
done: false
}
//值不存在,证明遍历已经结束
} else {
return {
done: true
}
}
}
}
}
for (let item of obj) {
console.log(item);
}
总结
尽量使用第一种方式吧,比较好理解一点,第二种则比较繁琐,需要对原生可遍历对象的结构比较了解。