ES6:Generator & Iterator

89 阅读3分钟

Generator函数

Generator函数可以理解为一个可以暂停执行的函数, 通过调用这个函数可以返回一个遍历器对象,然后再通过这个遍历器对象再分步的执行这个Generator函数。 先看一下它的代码

function* gen(){//Generator函数
	let x = 5;
	 x += yield 10;
	
	console.log(x);//30
}

let g1 = gen();
console.log(g1.next());//{value:10,done:false}
console.log(g1.next(25));//{value:undefined,done:true}

最终控制台输出的是

{value:10,done:false}
30
{value:undefined,done:true}

这里简单解释一下,首先我们用function + 一个*定义了Generator函数,这是定义Generator函数的一般形式,

然后我们使用了let g1 = gen();将这个函数的遍历器对象赋值给了g1,通过调用了g1的next方法,我们才能开始执行这个函数,并让其执行到了第一个yield位置,第一个yield后面跟了个10表示返回这个10,所以控制台第一个输出为{value:10,done:false},value即我们返回的值,done代表这个函数是否已经被执行完

注意此时我们的函数停留在了第一个yield的位置x += yield 10; 此时的x并没有开始赋值,直到我们调用了第二次的next函数,g1.next(25),这里我们传了一个参数进去,这个参数可以理解为赋值给了上一次停止的yield,所以x += yield 10的yield是有值的,值为25,所以最终x的值为30,控制台输出了30,然后再输出{value:undefined,done:true},函数执行完毕。

到这里应该能大致的知道Generator函数是怎么用得了吧

yield

  • 有点像return 不过它可以接受参数也可以返回值也可以暂停函数执行
  • 不能在普通函数中使用yield
  • yield如果放在另一个表达式中要加圆括号,简单的说就是你最好把yield和要返回的值用圆括号括起来,否则如果在其他表达式中直接使用yield会报语法错误
  • 可以用作为函数参数,不用加括号
  • 单独放在赋值表达式右边也不用加括号

yield*:yield后面加个星号用于遍历那些可遍历的对象比如数组,字符串或者Generator函数的遍历器等 看一段代码

function* g(){
    yield "hi"
    yield "sayhi"
}
function* h(){
    yield "hello"
    yield* g()
}

let h1 = h()
h1.next();//hello
h1.next();//hi
h1.next();//sayhi

从以上输出结果可以知道,yield*可以在Generator函数内部去遍历另一个Generator函数,效果等同于在函数内部使用for...of遍历

Iterator

Iterator是一种接口,为不同的数据结构提供统一的访问机制,只要数据结构中部署了Iterator接口,就能完成遍历操作。 当使用for..of循环遍历某种数据结构时,该循环会自动寻找Iterator接口,默认的Iterator接口放在数据结构的Symbol.iterator属性中

let obj = {
	[Symbol.iterator] : function(){
		return {
			next:function(){
				return {value:1,done:true}
			}
		}
	}
}

上面的obj对象就是一个可遍历的对象,因为它具有Symbol.iterator属性

原生具备Iterator接口的数据结构如下:

  • Array
  • Map
  • Set
  • String
  • TypedArray
  • 函数的arguments对象
  • Nodelist对象
let arr = [1,2,3,4]
let iter = arr[Symbol.iterator]();
iter.next();//{value:1,done:false}
iter.next();//2
iter.next();//3
iter.next();//4

想要更详细的了解Iterator可以参考阮一峰大神的文章 文章连接