Iterator 和 for...of 循环

Iterator 概念

Javascript 原有的表示集合的"数据"结构,主要是 数组 Array 、Object 、Map、Set。 这四种数据集合,用户还可以组合使用他们,定义自己的数据结构,不如数组的成员是Map,Map的成员是对象。这样子就需要一种统一的接口机制,来处理不同的数据结构。

遍历器(Iterator)就是这样一种机制。它是一种接口,为各种不同的数据结构提供同一的访问机制。任何数据结构只要部署Iterator接口,就可以完成遍历操作;

Iterator的作用有三个:
1、为各种数据结构,提供一个统一的、简单的访问接口;
2、使得数据结构的成员能够按某种次序排列;
3、ES6创造了一种新的遍历命令 for…of循环;

Iterator 的遍历过程是这样的。

  1. 创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
  2. 第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。
  3. 第二次调用指针对象的next方法,指针就指向数据结构的第二个成员
  4. 不断调用指针对象的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);
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值