迭代器和生成器

一.迭代器

1.迭代器是带有特殊接口的对象,返回一个next方法,该方法中同时又valuedone属性,当再没有值能够迭代时,valueundefineddonetrue,不然value为当前值,donefalsejavascript

2.根据上面的描述实现一个迭代器,以下:java

let iterator = {
	i: 0,
	items: [2, 4, 6],
	next() {
		let value, done;
		done = (this.i === this.items.length);
		value = done ? undefined : this.items[this.i++];
		return {
			value: value,
			done: done
		}
	}
};
console.log(iterator.next());  //{value: 2, done: false}
console.log(iterator.next());  //{value: 4, done: false}
console.log(iterator.next());  //{value: 6, done: false}
console.log(iterator.next());  //{value: undefined, done: true}
复制代码

二.生成器

1.生成器是返回迭代器的函数,以下:数组

function *createIterator() {
	yield 1;
	yield 2;
	yield 3;
}
let iterator = createIterator();
console.log(iterator.next());  //{value: 1, done: false}
console.log(iterator.next());  //{value: 2, done: false}
console.log(iterator.next());  //{value: 3, done: false}
console.log(iterator.next());  //{value: undefined, done: true}
复制代码

2.生成器有几点要注意的:函数

  • 当执行流遇到yield语句时,该生成器就中止运转了,直到迭代器再次调用next
  • 能够再for循环中使用yield
  • yield只能用在生成器的内部,即便是生成器内部的函数也不行,即:yield没法跨越函数边界
  • 没法使用箭头函数建立生成器
  • 生成器能够存在于对象的属性中

三.for-of循环

1.可迭代类型:指那些包含Symbol.iterator属性的对象,该属性定义了返回迭代器的函数(如:数组,set,map等)ui

2.for-of循环能够循环可迭代类型,for-of循环会在可迭代类型每次执行后调用next()并将结果存储在变量中,循环会持续进行,直到结果对象的done属性为truethis

3.for-of循环会调用数组的Symbol.iterator属性来获取迭代器(该方法由幕后的js引擎调用),并将调用iterator.next(),并将该结果对象的value属性的值赋给num,直到done为true,循环会退出,num不会被赋给undefined,代码以下:spa

let values = [1, 2, 3];
for (let item of values) {
	console.log(item);   //1 2 3
}
复制代码

4.对于非可迭代对象,如nullundefined,使用for-of循环会抛出错误代理

5.能够在for-of循环中使用解构code

let map = new Map();
map.set('name', 'sxt');
map.set('age', 2);
for(let [key, value] of map) {
	console.log(key + " = " + value);
}
//输出:
//name = sxt
//age = 2
复制代码

6.for-of循环能够用于循环NodeList对象

四.Symbol.iterator

1.能够用Symbol.iterator属性来访问对象默认的迭代器,如:

let arr = [6, 7, 8];
let iterator = arr[Symbol.iterator]();
console.log(iterator.next());  //{value: 6, done: false}
console.log(iterator.next());  //{value: 7, done: false}
console.log(iterator.next());  //{value: 8, done: false}
console.log(iterator.next());  //{value: undefined, done: true}
复制代码

2.判断一个对象是否能够迭代,能够经过判断Symbol.iterator属性是不是一个函数来实现,如:

function isIterator(obj) {
	return typeof obj[Symbol.iterator] === 'function';
}

let arr = [1, 3, 4];
let num = 1;
console.log(isIterator(arr)); //true
console.log(isIterator(num)); //false
复制代码

3.建立可迭代类型: 咱们本身定义的对象默认是不可迭代类型,可是咱们能够经过设置Symbol.iterator属性来使这个对象能够迭代。由于前面第3点有讲到,判断一个对象是否能够迭代,实际上是经过Symbol.iterator属性来肯定的,由此能够建立下面的对象

let obj = {
	*[Symbol.iterator]() {
		yield 1;
		yield 2;
		yield 3;
	}
};
for (let item of obj) {
	console.log(item);  //1 2 3
}
复制代码

五.内置迭代器

1.咱们日常迭代数组,set和map时,能拿到迭代的值,是由于这些集合中有内置的迭代器,如

let arr = [1, 3, 5];
let set = new Set();
set.add('time');
set.add('user');
set.add('family');
let map = new Map();
map.set('name', 'sxt');
map.set('age', 12);
map.set('sister', 'andy');

for(let item of arr) {
	console.log(item);  // 1 3 5
}
for(let item of set) {
	console.log(item); //time user family
}
for(let item of map) {
	console.log(item); //["name", "sxt"] ["age", 12] ["sister", "andy"]
}
复制代码

2.内置迭代器分为三种

  • entries()
  • keys()
  • values()

3.数组的entries返回的是[索引,值],set的entries是[值,值],由于set的键值是同样的,map的entries是[键名,键值],如:

let arr = [1, 3, 5];
let set = new Set();
set.add('time');
set.add('user');
set.add('family');
let map = new Map();
map.set('name', 'sxt');
map.set('age', 12);
map.set('sister', 'andy');

for(let item of arr.entries()) {
	console.log(item);  // [0, 1] [1, 3] [2, 5]
}
for(let item of set.entries()) {
	console.log(item); //["time", "time"] ["user", "user"] ["family", "family"]
}
for(let item of map.entries()) {
	console.log(item); //["name", "sxt"] ["age", 12] ["sister", "andy"]
}
复制代码

4.数组的keys返回的索引,set的keys返回的仍是值,map的keys返回的是值 5.数组,set,map的values返回的都是值

六.向迭代器中传递参数

1.咱们能够向迭代器中传递参数

function *createIterator() {
	let first = yield 1;
	let second = yield first + 2;
	yield second + 3;
}

let iterator = createIterator();
console.log(iterator.next());   //{value: 1, done: false}
console.log(iterator.next(4));  //{value: 6, done: false}
console.log(iterator.next(5));  //{value: 8, done: false}
console.log(iterator.next());   //{value: undefined, done: true}
复制代码
  • 这里的难点是理解右侧的代码会和左边的中断
  • 首次调用next的时候,无论传入什么参数都会被忽略,由于传入的参数会做为yield语句的返回值,而第一次只是yield 1,而没有变量

七.包含return语句的生成器

function *createIterator() {
	yield 1;
	return 133;
	yield 2;
	yield 3;
}

let iterator = createIterator();
console.log(iterator.next());   //{value: 1, done: false}
console.log(iterator.next(4));  //{value: 133, done: true}
console.log(iterator.next(5));  //{value: undefined, done: true}
console.log(iterator.next());   //{value: undefined, done: true}

复制代码
  • return会让它提早执行完毕并针对next的调用返回一个值

八.生成器代理

1.即,在一个生成器中调用另外的生成器,有时候,这样的操做会更加的实用

function *create1() {
	yield 1;
	yield 2;
	yield 3;
}

function *create() {
	yield *create1();
	yield true;
}


let iterator = create();
console.log(iterator.next());  //{value: 1, done: false}
console.log(iterator.next());  //{value: 2, done: false}
console.log(iterator.next());  //{value: 3, done: false}
console.log(iterator.next());  //{value: true, done: false}
console.log(iterator.next());  //{value: undefined, done: true}
复制代码
相关文章
相关标签/搜索