Iterator 概念
Javascript 原有的表示集合的"数据"结构,主要是 数组 Array 、Object 、Map、Set。 这四种数据集合,用户还可以组合使用他们,定义自己的数据结构,不如数组的成员是Map,Map的成员是对象。这样子就需要一种统一的接口机制,来处理不同的数据结构。
遍历器(Iterator)就是这样一种机制。它是一种接口,为各种不同的数据结构提供同一的访问机制。任何数据结构只要部署Iterator接口,就可以完成遍历操作;
Iterator的作用有三个:
1、为各种数据结构,提供一个统一的、简单的访问接口;
2、使得数据结构的成员能够按某种次序排列;
3、ES6创造了一种新的遍历命令 for…of循环;
Iterator 的遍历过程是这样的。
- 创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
- 第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。
- 第二次调用指针对象的next方法,指针就指向数据结构的第二个成员
- 不断调用指针对象的next方法,知道他指向数据结构的结束为止。
每一次调用next方法,都会返回数据结构的当前成员的信息。具体来说,就是返回一个包含value和done两个属性的对象。 其中value属性是当前成员的值,done属性是一个布尔值,表示遍历是否结束。
for…of
ES6引入for…of循环,作为遍历所有数据结构的统一的方法。
一个数据结构只要部署了Symbol.iterator
属性,就被视为具有iterator接口,就可以用 for...of
循环遍历它的成员。
也就是说, for...of
循环内部调用的是数据结构的Symbol.iterator
方法。
for...of
循环可以使用的范围包括数组、Set和 Map结构、某些类似数组的对象(比如arguments对象、DOM Nodelist对象)、后文的Generator 对象,以及字符串。
数组
数组原生具备iterator接口(即默认有Symbol.iterator属性),for…of循环本质上就是调用这个接口产生的遍历器。
let arr = ['red','green', 'blue'];
for(let val of arr){
console.log(val); // red green blue
};
1、for...of
循环可以代替数组实例的forEach
方法。
const arr = ['red', 'green', 'blue'];
arr.forEach((ele,i)=>{
console.log(ele); // red green blue
console.log(i); // 0 1 2
});
2、JavaScript原有的for...in
循环,只能获得对象的键名,不能直接获取键值。ES6提供了for...of
循环,允许遍历获得键值。
var arr = ['a', 'b', 'c', 'd'];
for (let a in arr) {
console.log(a); // 0 1 2 3
}
for (let a of arr) {
console.log(a); // a b c d
}
上面的代码表明,for...in
循环读取键名,for...of
循环读取键值。如果摇通过for...of
循环,获取数组的索引,可以借助数组实例的 entries
方法和keys
方法。
3、for...of
循环调用遍历器接口,数组的遍历器接口只返回具有数字索引的属性。这一点跟for...in
循环不一样。
let arr = [3, 5, 7];
arr.foo = 'hello';
for (let i in arr) {
console.log(i); // "0", "1", "2", "foo"
}
for (let i of arr) {
console.log(i); // "3", "5", "7"
}
上面代码中,for...of
循环不会返回数组arr的foo属性。
对象
对象默认不能进行for of循环,因为没有遍历器。直接使用会报错;
解决办法:
使用`Object.keys``方法将对象的键名生成一个数组,然后遍历这个数组。
let arr = ['red','green', 'blue'];
const obj = {};
obj[Symbol.iterator]= arr[Symbol.iterator].bind(arr);
for(let val of obj){
console.log(val); // red green blue
};
上面的代码中,空对象obj部署了数组arr的Symbol.iterator
属性,所以可以使用;
第二种:
let obj = {
name:'蓝蓝',
age:17
}
obj[Symbol.iterator] = function(){
let keys = Object.keys(obj); // ['name','age']
let len = keys.length; 2
let i = 0;
return{
next(){
if(i<len){
return{value:{key:keys[i],val:obj[keys{i++]]},done:false}else{
return{done:true};
}
}
}
}
let iter = obj[Symbol.iterator]();
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
遍历接口返回一个对象,对象中有一个next方法,这个方法必须return对象,在这个对象下有2个属性 value,done
- value 就是for of中的attr
- done:为true的时候不遍历;
- done;为false的时候遍历;
Object.prototype[Symbol.iterator] = function(){
let keys = Object.keys(this);
let len = keys.length;
let i = 0;
let that = this;
return {
next(){
if(i < len){
return {done:false,value:{key:keys[i],val:that[keys[i++]]}}
}else{
return {done:true}
}
}
}
}
for(let {key,val} of obj){
console.log(key,val);
};