Iterator是一种接口,为不同的数据结构提供统一的数据访问机制。 for...of是ES6引入的一种遍历所有数据接口的方法。
Iterator有何用途
- 为各种数据提供统一的接口;
- 使得数据结构的成员能够按照某种次序排列;
- 为for...of服务,供for...of消费。
Iterator概念
var it = makeIterator(['a', 'b']);
it.next() // { value: "a", done: false }
it.next() // { value: "b", done: false }
it.next() // { value: undefined, done: true }
function makeIterator(array) {
var nextIndex = 0;
return {
next: function() {
return nextIndex < array.length ?
{value: array[nextIndex++], done: false} :
{value: undefined, done: true};
}
};
}
注释:
- makeIterator函数是一个遍历器生成函数,作用就是返回一个遍历器对象it。
- next方法是用来移动位置的,每次调用都会返回一个对象{value:'', done:true/false},value就是返回当前遍历位置的值,done表示是否遍历结束。
Iterator接口实现
一种数据结构只要部署了 Iterator 接口,我们就称这种数据结构是“可遍历的”(iterable)。ES6规定,默认的 Iterator 接口部署在数据结构的Symbol.iterator属性。
已默认部署 Iterator 接口的对象主要包括Array、String、Set、Map 、类似数组的对象(如arguments对象、DOM NodeList对象)。
对象(Object)之所以没有默认部署 Iterator 接口,是因为对象的哪个属性先遍历,哪个属性后遍历是不确定的,需要开发者手动指定。
对象Iterator接口实现
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 (var val of obj) {
console.log(val);
}
// 打印键值"hello"、"world"
Iterator应用场景
- 解构赋值
var iterableObj = {
items: ['红','绿','蓝'],
[Symbol.iterator]: function () {
var self = this;
var i = 0;
return {
next: function () {
var done = (i >= self.items.length);
var value = !done ? self.items[i++] : undefined;
return {
done: done,
value: value
};
}
};
}}
var [d,e] = iterableObj;
console.log(d,e);//红 绿
- 扩展运算符(...)
- yield*
for...of运行机制
执行for...of其实就是调用遍历器生成函数,然后依次执行遍历器对象的next方法,将next方法返回的值(value)赋值给for...of中的变量。
for in和for of
- for in遍历数组的键名,for of 遍历的是数组的键值。
var myObject ={
a:'1',
b:'2',
c:'3'
}
myObject.__proto__.d = '4';
for (var key in myObject) {
if(myObject.hasOwnProperty(key)){
console.log(key);
}
}
// 只打印实例属性的键名"a"、"b"、"c"
var myArray = ['1','2','3']
for (var val of myArray) {
console.log(val);
}
// 打印键值"1"、"2"、"3"
- for in
(1)遍历顺序不一定
(2)遍历所有可枚举的属性,包括原型上的属性和方法
for in更适合遍历对象,不适合遍历数组;遍历对象时,如果不想要原型上的属性和方法,可以通过hasOwnProperty来判断该属性是不是实例的属性,这实际上跟Object.keys(myObj)得到的结果一样。
- for of
更适合遍历数组、数组对象、字符串、Map、Set等拥有迭代器对象的集合,但是不能遍历对象,如果要遍历,需要实现Symbol.interator属性;
相对于forEach,可以响应break、continue、return语句。