木子屋 Dnawo's BLOG

ES6学习笔记:Iterator接口和Generator函数

👤 dnawo 📅 2022-04-12 👁 2812 👍 0 💬 0 🔄 来源:本站原创
一、Iterator接口

Iterator接口为各种不同的数据结构提供统一的访问机制,任何数据结构只要部署了Iterator,就可以完成遍历操作,举个例子:

function customIterator(arr) {
	let nextIndex = 0;
	return {
		next: function() {
			if(nextIndex < arr.length){
				return {value: arr[nextIndex++], done: false};
			}else{
				return {value: undefined, done: true};
			}
		}
	};
}

let it = customIterator(['a', 'b']);
it.next(); //{value: 'a', done: false }
it.next(); //{value: 'b', done: false }
it.next(); //{value: undefined, done: true }

customIterator是实现Iterator接口的遍历器生成函数,调用该函数会返回一个遍历器,其内部有一个指针和一个next方法,每一次调用next方法都会移动指针和返回数据结构当前成员的信息,返回值是一个对象,格式为:{value, done},value是当前成员的值,done是一个布尔值,表示遍历是否结束。

对于Array、Map、Set、String、TypedArray、函数的arguments对象、NodeList对象这些数据结构,Javascript原生给它们部署了Iterator,调用这些数据结构的Symbol.iterator属性即可得到遍历器生成函数:

let arr = ['a', 'b'];
let it = arr[Symbol.iterator]();
it.next(); //{value: 'a', done: false }
it.next(); //{value: 'b', done: false }
it.next(); //{value: undefined, done: true }

二、Generator函数

Generator函数也是一个遍历器生成函数,它的实现方式和Iterator接口完全不同。Generator函数有两个特征,一是function关键字与函数名之间有一个星号,二是函数体内部使用yield表达式,定义不同的内部状态,每一次调用next方法运行到下一个yield并暂停,返回值和Iterator一样,value为yield表达式的值:

function* customGenerator() {
	yield 'a';
	yield 'b';
}

let gt = customGenerator();
gt.next(); //{value: 'a', done: false }
gt.next(); //{value: 'b', done: false }
gt.next(); //{value: undefined, done: true }

换言之,Generator函数是分段执行的,yield表达式是暂停执行的标记,而next方法可以恢复执行。Generator函数调用时不会立即执行,直到调用next方法才开始执行。利用Generator函数这个特性,我们可以写出任意对象遍历器:

function* customGenerator(obj) {
	let propKeys = Reflect.ownKeys(obj);

	for (let propKey of propKeys) {
		yield [propKey, obj[propKey]];
	}
}

let gt = customGenerator({name: 'Jack', age: 30});
gt.next(); //{value: ['name', 'Jack'], done: false }
gt.next(); //{value: ['age', 30], done: false }
gt.next(); //{value: undefined, done: true }

Generator函数也是一个遍历器生成函数,所以将它加到对象的Symbol.iterator属性上面也是可以的:

let person = {
	name: 'Jack', 
	age: 30,
	[Symbol.iterator]: function* () {
	    let propKeys = Object.keys(this);

	    for (let propKey of propKeys) {
	        yield [propKey, this[propKey]];
	    }
	}
};

let gt = person[Symbol.iterator]();
gt.next(); //{value: ['name', 'Jack'], done: false }
gt.next(); //{value: ['age', 30], done: false }
gt.next(); //{value: undefined, done: true }

三、for...of循环

一个数据结构只要部署了Symbol.iterator属性,就被视为具有iterator接口,就可以用for...of循环遍历它的成员:

for(let item of arr){
	console.log(item);
}
//a
//b

for(let item of person){
	console.log(item);
}
//['name', 'Jack']
//['age', 30]

评论(0)

暂无评论。

验证码
评论需审核通过后显示
← 上一篇 ES6学习笔记:Proxy对象 下一篇 → ES6学习笔记:Module模块