系列链接:
js遍历对象篇(一)-for...in和Object.keys
Iterator(遍历器)
ES6 规定,默认的 Iterator 接口部署在数据结构的Symbol.iterator属性(指向该对象的默认遍历器方法),或者说,一个数据结构只要具有Symbol.iterator属性,就可以认为是“可遍历的”(iterable)。Symbol.iterator属性本身是一个函数,就是当前数据结构默认的遍历器生成函数。执行这个函数,就会返回一个遍历器。至于属性名Symbol.iterator,它是一个表达式,返回Symbol对象的iterator属性,这是一个预定义好的、类型为 Symbol 的特殊值,所以要放在方括号内。
原生具备 Iterator 接口的数据结构如下:
- Array
- Map
- Set
- String
- TypedArray
- 函数的 arguments 对象
- NodeList 对象 以上Iterator相关介绍文字引自阮一峰老师ES6教程
let arr = ['a', 'b', 'c'];
let iter = arr[Symbol.iterator]();
console.log(iter.next()); // { value: 'a', done: false }
console.log(iter.next()); // { value: 'b', done: false }
console.log(iter.next()); // { value: 'c', done: false }
console.log(iter.next()); // { value: undefined, done: true }
添加iterator接口
1. 给对象添加iterator接口
for...of...遍历对象需要iterator接口
// 由于Object对象没有原生Iterator接口,无法遍历对象
// const obj = {
// name: 'lsc',
// age: 21
// }
// for (let item of obj) {
// console.log(item); // TypeError: obj is not iterable
// }
// 给对象添加iterator接口
const obj2 = {
name: 'lsc',
age: 21,
height: 187,
[Symbol.iterator] () {
const self = this
const keys = Object.keys(self)
let index = 0
return {
next() {
if (index < keys.length) {
return {
value: self[keys[index++]],
done: false
}
} else {
return {value: undefined, done: true}
}
}
}
}
}
for (let item of obj2) {
console.log(item);
}
2. 给类数组添加iterator接口
arguments/nodelist等常见伪数组本身就有iterator接口,所以这里记录原生伪数组
// 手写伪数组 此例子源于阮一峰ES6教程
let iterable = {
0: 'a',
1: 'b',
2: 'c',
length: 3,
[Symbol.iterator]: Array.prototype[Symbol.iterator]
};
for (let item of iterable) {
console.log(item); // 'a', 'b', 'c'
}
但更简便的方法是用扩展运算符或Array.from将伪数组直接转化为数组
Generator
Generator既是状态机,又是遍历器生成函数,因此可以把Generator赋值给对象的Symbol.iterator属性
const obj2 = {
name: 'lsc',
age: 21,
height: 187,
[Symbol.iterator]: function* myIterator(){
for(let key of Object.keys(this))
yield this[key];
}
}
for (let item of obj2) {
console.log(item); // lsc 21 187
}