JavaScript迭代器的含义及用法(3)

let map = new Map([[1,2],[3,4]]) let mapEntires = map.entries() mapEntires.next() //{value: [1, 2], done: false} let mapKeys = map.keys() mapKeys.next() //{value: 1, done: false} let mapValues = map.values() mapValues.next() //{value: 2, done: false}

Map 的默认迭代器接口[Symblo.iterator]是 entries;

for(let item of new Map([[1,2],[3,4]])){ console.log(item)// [1,2] [3,4] }

为什么对象没有内置迭代器接口

在上面中,我们提及到对象没有设置可迭代的默认方法,是不可迭代对象,表现为其没有[Symbol.iterator]属性。虽然对象对我们来说,是键值存储的一种方式,尽管没有 map 那么好,key只可以是字符串,但是有的时候对象也是需要被迭代的,但是为什么不给对象设置可迭代的默认方法?

原因是因为,对于对象的遍历,需要考虑到遍历是对象自身的属性还是遍历对象自身上的可枚举属性还是遍历原型上的属性还是遍历原型上的可枚举属性还是连[Symbol.iterator]也希望遍历出来。鉴于各方意见不一,并且现有的遍历方式可以满足,于是标准组没有将[Symbol.iterator]加入。

生成迭代器对象的方法

在上面,我们尝试过了为一个对象添加了Symbol.iterator方法,该方法就是该对象的遍历器生成函数,调用该函数会返回该对象的一个遍历器对象。

除了上面在为对象添加遍历器生成函数的这种根据迭代器协议直接生成迭代器对象的方式外,还有什么方式可以生成迭代器对象呢?有,它是一种特殊的函数,叫生成器。

var it = {}; it[Symbol.iterator] = function* () { yield 1; yield 2; yield 3; }; //可以被...遍历,说明已经部署成功 console.log([...it])// [1, 2, 3] let myIterator = it[Symbol.iterator]() console.log(myIterator.next())//{value: 1, done: false} console.log(myIterator.next())//{value: 2, done: false} console.log(myIterator.next())//{ value: 3, done: false } console.log(myIterator.next())//{ value: undefined, done: true }

上面代码中,生成器函数没有过多的代码,只需要使用关键字yeild来返回每次next()的值。

生成器是一种特殊的函数形式,生成器函数的声明语法为:

function *bar(){ // ... }

*前后可以有空格也可以没有空格。生成器函数的声明虽然和普通函数有区别,但是执行和普通函数一样,一样可以传参数。那它们的主要区别是什么呢?

函数是一段执行特定任务的代码块,所以函数执行,相当于这一段代码块被执行。函数开始执行,在它执行完之前不会被打断,这段代码块将被全部执行完。在ES6引入生成器之前函数的确是这样执行的,但是前面介绍到外部迭代器可以相比内部迭代器对迭代过程进行控制,什么时候需要消耗,迭代器对象再next一下即可。类似迭代过程,函数的执行过程一样可以控制,函数可以不需要一次性执行完毕。

生成器函数的执行会返回一个迭代器对象来控制该生成器函数执行其代码。因此,函数的执行变得可控。还可以在生成器中使用新的关键字yield,用来标示一个暂停点。迭代器除了可以控制函数执行外,还可以在每一次暂停中双向传递信息,暂停的时候生成器函数会返回一个值,恢复执行的时候迭代器可以通过向next方法传参向函数内部传递一个值。可以理解为多次传参,多个返回值。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/2c8781c41d831c008a099d571a44dd0d.html