ES6 添加了Map和Set。这样就有了四种数据集合,需要一种统一的接口机制来处理所有不同的数据结构。遍历器(Iterator)就是这样一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成for...of遍历操作(即依次处理该数据结构的所有成员)。
总结:
Iterator 接口的目的,就是为所有数据结构提供了一种统一的访问机制,即for...of循环(详见下文)。当使用for...of循环遍历某种数据结构时,该循环会自动去寻找 Iterator 接口。
var it = makeIterator([1, 2, 3]);
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());
function makeIterator(arr) {
var nextIndex = 0;
return {
next: function () {
// 函数必须return
return nextIndex < arr.length ?
{ value: arr[nextIndex++], done: false }
: { value: undefined, done: true }
}
}
}
换句话说就是一个数据结构只要具有Symbol.iterator属性(本身是一个函数),就可以认为是“可遍历的”(for...of)(重中之中不好理解多讲一遍)
Symbol.iterator属性本身是一个函数,就是当前数据结构默认的遍历器生成函数。执行这个函数,就会返回一个遍历器对象(该对象的根本特征就是具有next方法。每次调用next方法,都会返回一个代表当前成员的信息对象,具有value和done两个属性。)。至于属性名Symbol.iterator,它是一个表达式,返回Symbol对象的iterator属性
(对象的Symbol.iterator属性,指向该对象的默认遍历器方法。)
const obj = {
[Symbol.iterator] : function () {
return {
next: function () {
return {
value: 1,
done: true
};
}
};
}};
ES6 的有些数据结构原生具备 Iterator 接口(比如数组),即不用任何处理,就可以被for...of循环遍历。原因在于,这些数据结构原生部署了Symbol.iterator属性,另外一些数据结构没有(比如对象)。凡是部署了Symbol.iterator属性的数据结构,就称为部署了遍历器接口。调用这个接口,就会返回一个遍历器对象。
原生具备 Iterator 接口的数据结构如下。
// 例如数组的Symbol.iterator属性。
let arr = ['a', 'b', 'c'];
let iter = arr[Symbol.iterator]();
console.log(iter.next());// { value: 'a', done: false }
console.log(iter.next());// { value: 'a', done: false }
console.log(iter.next());// { value: 'a', done: false }
console.log(iter.next());// { value: undefined, done: true }
arguments对象不是一个 Array 。它类似于Array,但除了长度之外没有任何Array属性。例如,它没有 pop 方法。
但是它可以被转换为一个真正的Array:(arguments转为真正的数据,ES5用slice()方法,ES6扩展运算符)
var args = Array.prototype.slice.call(arguments);
var args = [].slice.call(arguments);
// ES2015
const args = Array.from(arguments);
function get(a,b,c){
console.log(arguments);
console.log(Array.from(arguments)); // [1,2,3] 实参
return a+b+c
}
get(1,2,3)
对于原生部署 Iterator 接口的数据结构,不用自己写遍历器生成函数,for...of循环会自动遍历它们。
除此之外,其他数据结构(主要是对象)的 Iterator 接口,都需要自己在Symbol.iterator属性上面部署,这样才会被for...of循环遍历。
原因:对象(Object)之所以没有默认部署 Iterator 接口,是因为对象的哪个属性先遍历,哪个属性后遍历是不确定的,需要开发者手动指定。
如果对象想具备Iterator 接口需要自己在Symbol.iterator属性上面部署,这样才会被for...of循环遍历。
给自身obj一个Symbol.iterator函数;
给定遍历顺序,此处为data.length的不断递进
let obj = {
data: [ 'hello', 'world' ],
[Symbol.iterator]() {
const self = this;
let index = 0;
return {
next() {
if (index < self.data.length) {
return {
value: self.data[index++],
done: false
};
} else {
return { value: undefined, done: true };
}
}
};
}
}
for (let value of obj) {
console.log(value);
}