Iterator ( 遍历器 ) 的概念
JavaScript原有的表示"集合"的数据结构, 主要有数组 ( Array ) 和对象 ( Object ), ES6又天津爱了Map和Set. 这样就有了四种数据集合,用户还可以组合使用它们,定义自己的数据结构,比如数组的成员是Map, Map的成员是对象.这样就需要一种统一的接口机制,来处理所有不同的数据结构.
遍历器 ( Iterator ) 就是这样一种机制. 它是一种接口,为各种不同的数据结构提供统一的访问机制. 任何数据结构只要部署 Iterator 接口,就可以完成遍历操作 ( 即依次处理该数据结构的所有成员 ).
Iterator 的作用有三个: 一是为各种数据结构,提供一个统一的,简单的访问接口; 二是使得数据结构的成员能够按某种次序排列; 三是 ES6 创造了一种新的遍历命令for...of
循环, Iterator 接口主要供for...of
消费.
Iterator 的遍历过程是这样的:
( 1 ) 创建一个指针对象, 指向当前数据结构的起始位置. 也就是说,遍历器对象本质上, 就是一个指针对象.
( 2 ) 第一次调用指针对象的next
方法, 可以将指针指向数据结构的第一个成员.
( 3 ) 第二次调用指针对象的next
方法, 指针就指向数据结构的第二个成员.
( 4 ) 不断调用指针对象的next
方法, 直到它指向数据结构的结束位置.
每一次调用next
方法, 都会返回数据结构的当前成员的信息. 具体来说, 就是返回一个包含value
和done
两个属性的对象. 其中,value
属性是当前成员的值,done
属性是一个布尔值, 表示遍历是否结束.数据结构的默认 Iterator 接口
Iterator接口的目的, 就是为所有数据结构, 提供了一种统一的访问机制, 即
for...of
循环.当使用for...of
循环遍历某种数据结构时,该循环会自动去寻找 Iterator 接口.
ES6 规定, 默认的 Iterator 接口部署在数据结构的Symbol.iterator
属性, 或者说, 一个数据结构只要具有Symbol.iterator
属性, 就可以认为是"可遍历的". 调用Symbol.iterator
本身是一个表达式, 返回 Symbol 对象的 iterator 属性, 这是一个预定义好的,类型为 Symbol的特殊值, 所以要放在方括号内.对象 ( Object ) 之所以没有默认部署 Iterator 接口, 是因为对象的哪个属性先遍历, 哪个属性后遍历是不确定的, 需要开发者手动指定. 本质上, 遍历器是一种线性处理,对于任何非线性的数据结构, 部署遍历器接口, 就等于部署一种线性转换. 不过, 严格地说, 对象部署遍历器接口并不是很必要, 因为这时对象实际上被当做 Map 结构使用, ES5没有Map结构, 而ES6原生提供了.
let obj = {
id: '123',
name: '张三',
age: 18,
gender: '男',
hobbie: '睡觉'
}
obj[Symbol.iterator] = function () {
let keyArr = Object.keys(obj)
let index = 0
return {
next() {
return index < keyArr.length ? {
value: {
key: keyArr[index],
val: obj[keyArr[index++]]
}
} : {
done: true
}
}
}
}
for (let key of obj) {
console.log(key)
}