for (let stu of students){}
// Uncaught TypeError: students is not iterable
复制代码is not iterable,这个iterable是神马东西,我们接下来下面一步步的看。
先从可迭代(iterable)和迭代器(iterator)说起
iterable是ES6对iteration(迭代/遍历)引入的接口。
如果一个对象被视为iterable(可迭代)那么它一定有一个Symbol.iterator属性,这个属性返回一个iterator(迭代器)方法,这个方法返回一个规定的对象(这个后面会说)。也就是说iterable是iterator的工厂,iterable能够创建iterator。iterator是用于遍历数据结构中元素的指针。
两者之间的关系
Axel Rauschmaye大神的图简直不能再清晰了。
foo.prototype.sayName = function() {
return this.name;
}
var o = new foo();
for (var i in o) {
console.log(i)
}
// name
// sayName
复制代码如果我们只想遍历对象自身的属性,可以使用hasOwnProperty,如下:
function foo() {
this.name = 'helios'
}
foo.prototype.sayName = function() {
return this.name;
}
var o = new foo();
for (var i in o) {
if (!o.hasOwnProperty(i)) continue;
console.log(i)
}
复制代码如果我们不想让一个对象的属性,在for...in中不被遍历出来,可是使用Object.defineProperty来定义对象上的属性是否可别枚举(更多的属性请看:Object.defineProperty()),具体如下面代码:
var obj = {name: 'helios'}
function iterOver() {
let age = 23;
const iterable = {
[Symbol.iterator]() {return this},
next() {
return {
value: age,
done: age++ > 24
}
}
}
return iterable
}
for (let i of iterOver()) {
console.log(i)
}
复制代码现在生成器(generator)可以出场了
我们如果每次想把一个不能迭代的对象变为可迭代的对象,在实现Symbol.iterator的时候,每次都要写返回一个对象,对象里面有对应的next方法,next方法必须返回valua和done两个值。
这样写的话每次都会很繁,好在ES6提供了generator(生成器)能生成迭代器,我们来看简化后的代码:
复制代码让object可迭代真的有意义么
知乎的这个回答是很有水平的了:为什么es6里的object不可迭代?
在stackoverflow中也有很高质量的回答:Why are Objects not Iterable in JavaScript?
在上面的回答中从技术方面说了为什么Object不能迭代(没有实现iterable),还说了以什么样的方式去遍历Object是个难题,所以把如何迭代的方式去留给了开发者。
但是还是要思考的一个问题就是:我们真有必要去迭代对象字面量么?
想一下我们要迭代对象字面量的什么呢?是keys还是values亦或者是entries,这三种方式在ES6提供的新的数据类型map里面都有呀,完全是可以代替object的。在这里不说object和map的区别,只是说说在ES6以后我们想把两个事物关联起来的时候,不一定要非得是用对象字面量了,map支持的更好一下。
对于什么时候用对象字面量(object)什么时候使用map我们可以做一下总结: