这节课要讲的是ES6中的Iterator.

for...of为啥不遍历Object对象

第十三节我们讲了简单又实用的for...of,我们可以使用它来遍历数组,字符串,Set和Map结构,但是有没有发现,我们并没有说它可以遍历Object对象,为什么不试试用它来遍历Object对象呢?

我们试试看:

//定义一个的Object对象
let obj = {"name":"前端君"}; //咱们来for...of一下
for(let v of obj){
console.log(v);
}
//结果:报错
//错误提示:obj[Symbol.iterator]不是一个function

oh no,程序报错了,for...of根本不支持遍历普通的Object对象,还出现了错误提示:**obj[Symbol.iterator]不是一个function,**这是什么鬼?

为什么数组,Set和Map结构又可以支持for...of的遍历呢?

原来,要想能够被for...of正常遍历的,都需要实现一个遍历器Iterator。而数组,Set和Map结构,早就内置好了遍历器Iterator(又叫迭代器),它们的原型中都有一个Symbol.iterator方法;而Object对象并没有实现这个接口,使得它无法被for...of遍历。

那么,我们就亲自来验证一下,它们的原型中到底是不是有个叫Symbol.iterator的方法:

//数组
Array.prototype[Symbol.iterator];
//结果:function values(){...} //字符串
String.prototype[Symbol.iterator];
//结果:function [Symbol.iterator](){...} //Set结构
Set.prototype[Symbol.iterator];
//结果:function values(){...} //Map结构
Map.prototype[Symbol.iterator];
//结果:function entries(){...} //Object对象
Object.prototype[Symbol.iterator];
//结果:undefined

从上往下看,确实,唯独Object对象的原型上没有Symbol.iterator,返回了:undefined。其他的数据类型的原型上都含有一个名字叫Symbol.iterator的方法Function。

注意:Symbol.iterator 是Symbol 对象的 iterator 属性,是一个特殊的Symbol值,因此,**当它作为prototype对象属性名的时候,获取它的时候需要使用[ ]的形式: prototype[Symbol.iterator],不能使用点形式获取:prototype.Symbol.iterator。**原因是点形式会把后面的值当作是字符串类型处理,而不是Symbol类型。第十一节有介绍,点击查看。

也就说,只要一个数据结构拥有一个叫[Symbol.iterator]()方法的数据结构,就可以被for...of遍历,我们称之为:可遍历对象。比如:数组,字符串,Set和Map结构。

现在你该知道为什么文章第一个案例会出现错误提示:obj[Symbol.iterator]不是一个function 了吧,因为Object对象的原型上压根就没有[Symbol.iterator]() 方法啊。还打算报警吗?

既然我们知道拥有[Symbol.iterator]()方法就可以被遍历,我们就会好奇:[Symbol.iterator]方法到底做了什么这么牛逼,它的原理是什么?

Iterator遍历器的原理

当可遍历对象被for...of遍历的时候,[Symbol.iterator]()就会被调用,返回一个iterator对象。其中还有一个很重要的方法:next( );

   //数组:一个可遍历对象
let arr = ['a','b','c'];
//调用数组的Symbol.iterator()方法
let iter = arr[Symbol.iterator](); iter.next();
//结果:{value: "a", done: false} iter.next();
//结果:{value: "b", done: false} iter.next();
//结果:{value: "c", done: false} iter.next();
//结果:{value: undefined, done: true}

第1次调用next( )方法:返回数组的第1个元素:“a”,以及done的值为fasle,表示循环没有结束,继续遍历。

第2次调用next( )方法:返回数组的第2个元素:“b”,以及done的值还是为fasle,表示循环没有结束,继续遍历。

第3次调用next( )方法:返回数组的第3个元素:“c”,以及done的值依然为fasle,表示循环没有结束,继续遍历。

第4次调用next( )方法:返回的value值为undefined,以及done的值变成了true,表示遍历结束。

原来,for...of的原理就是:先调用可遍历对象的[Symbol.iterator]( )方法,得到一个iterator遍历器对象,然后就在遍历器上不断调用next( )方法,直到done的值为true的时候,就表示遍历完成结束了

自定义Iterator遍历器

既然有了[Symbol.iterator]()方法就算是可遍历对象,那么我给Object对象手动加上一个[Symbol.iterator]()方法,那么它是不是可以被for...of遍历了?

那我们就试试看,给一个Object对象加一个[Symbol.iterator]( )方法,看它是不是就能被for...of遍历了?

    //定义一个的Object对象
let obj = {
0:"我是0",
1:"我是1",
2:"我是2",
length:3,
//添加[Symbol.iterator]方法
[Symbol.iterator] : function() {
let _this = this;
let index = 0;
return {
next:() => {
let value = _this[index];
let done = (index >= _this.length);
index++;
return {value,done}
}
}
}
}; //咱们来for...of一下
for(let v of obj){
console.log(v);
}
//结果:"我是0"
// "我是1"
// "我是2"

上面这个案例也许你看了觉得很复杂,没看懂,没关系,我一起来分析它的结构就够了!

我们定义了一个Object对象,同时给它添加了[Symbol.iterator]()方法,并在[Symbol.iterator]()方法实现了next( )方法,next( )方法返回的对象包含了value属性和done属性。

具体细节如果不理解没关系,我们确实看到了给Object对象加上了[Symbol.iterator]()方法后,最后确实能被for...of遍历了。

这就是说,我们可以创建一个可遍历的对象,并且自定义它的遍历行为。或者说可以通过添加[Symbol.iterator]()方法,把一个不可遍历的Object对象,变成可遍历的对象。

Iterator遍历器的价值

新特性for...of之所以能够遍历各种不同的数据结构,正是因为这个数据结构都实现了Iterator遍历器接口,供for...of遍历。如果没有实现Iterator接口,则该数据结构无法被for...of遍历,比如:普通的Object对象。

本节小结

总结:Iterator遍历器为各种数据结构提供一个统一的遍历接口,使得for...of能够轻松简便地访问数据成员。 数据结构实现了Iterator接口,我们称之为可遍历对象。我们也可以自己创建可遍历对象并自定义遍历行为。
更多学习内容和干货请参考我的视频-我的空间
更多前端学习内容文章干货请关注我的专栏(不断更新)

阿里名厂标准web前端高级工程师教程目录大全,从基础到进阶,看完保证您的薪资上升一个台阶

在这里我给大家准备了很多的学习资料

其实你与阿里工程师的差距只差这些东西
明天我会拼了命的更新,加油!

最新文章

  1. ArcGIS Engine开发之地图基本操作(1)
  2. Could not instantiate bean class [java.util.List]: Specified class is an interface] with root cause
  3. SSH整合(Struts2+hibernate+spring)
  4. DOM操作方法的简单归纳
  5. 设计模式(3)--抽象工厂模式(Absrtact Factory Pattern)
  6. javascript匿名函数应用
  7. 弹出框以及提示插件lghdialog.js的使用
  8. C++中,指针数组和数组指针
  9. 分批次获取git for windows的源代码
  10. UILabel设置行间距和字间距并计算高度-b
  11. QDialog弹出一个窗口,改变窗口大小
  12. HDU 1213 How Many Tables(模板——并查集)
  13. 玩转web之ligerui(一)---ligerGrid重新指定url
  14. Ubuntu下解压压缩文件
  15. 深入理解Java虚拟机02--Java内存区域与内存溢出异常
  16. 五:python 对象类型详解二:字符串(上)
  17. Weblogic下启用Gzip压缩
  18. TCP系列47—拥塞控制—10、FACK下的快速恢复与PRR
  19. SQL Server清理Log文件
  20. 排除maven jar冲突 maven tomcat插件启动报错 filter转换异常

热门文章

  1. 使用datasest属性改变样式
  2. linux service 例子
  3. 各种杂记关于Linux
  4. K - 回转寿司(值域段数(板题) + 动态开点)
  5. MySQL 同步复制及高可用方案总结
  6. java+lodop+vue+热敏打印机,打印图片
  7. java类文件结构笔记
  8. php的 '1' == 1, 返回true,到底是谁变成了谁?
  9. iOS岗位招聘标准水涨船高,五年iOS程序员表示面试太难了
  10. Linux网络篇,ssh原理及应用