• 简介
  • 正文
  • 思考

    简介

    ES6中新增了一种遍历语法:for (... of ...) 来支持所有可遍历的数据结构

    for-of 是基于iterator这个通用接口实现的

    正文

    在ES6以前,我们想遍历一个数组一般有三种方式:

    • for 循环
    • for … in 语句
    • Array.prototype.forEach 方法

    三种方式都有不同程度的缺陷

    for循环写法繁琐,需要指定循环次数不超过数组长度,否则就会有对应的报错

    for … in 语句遍历出的是键值,需要做一些转换才能拿到数据,而且遍历是无序的

    forEach 方法是个不错的方式,不过它不能中途使用break跳出循环,也不能return终止外层函数

    基于这些缺陷,ES6新增了 for … of 的语法,用于遍历数组,对象,字符串,或者是Set,Map等数据结构

    for … of 遍历依赖 iterator 接口,只有部署了 iterator 接口的数据类型才可以被遍历

    iterator 接口是这些数据结构上的一个属性:Symbol.iterator,它是一个函数

    1. let iterator = [1, 2, 3][Symbol.iterator]()
    2. iterator // Array Iterator {}
    3. iterator.next()
    4. // {value: 1, done: false}
    5. iterator.next()
    6. // {value: 2, done: false}
    7. iterator.next()
    8. // {value: 3, done: false}
    9. iterator.next()
    10. // {value: undefined, done: true}

    Symbol.iterator显然是一个Symbol类型值,在Symbol章节介绍过,必须使用方括号访问

    调用数组上的 Symbol.iterator 方法,即可返回一个iterator遍历器对象

    这个 iterator 对象上只有一个常用方法 next ,每次调用 next 即可返回一个对象

    返回的对象有两个属性,value :当前遍历的值, done :是否遍历完毕

    这里必须说明一下为什么这个遍历器的属性名是一个很绕的Symbol类型

    其实最开始是打算叫做 iterator() 的 ,可是考虑到已有的代码中,可能已经有人用这个名字命名了一些属性

    ES6如果直接使用这个名字会造成兼容性问题,无奈之下只能使用绝对不可能重复的 [Symbol.iterator]()

    for…of 语句会在内部直接调用遍历对象上的 Symbol.iterator 方法

    并且每次循环中自动调用返回值的next方法,然后将next方法返回值的value属性值赋值给每次的循环变量

    1. for (let a of arr){
    2. console.log(a)
    3. }
    4. // 1 2 3

    正常情况下我们不会手动使用next方法去一个一个的拿到值

    而是使用 for … of 方便的遍历所有具有 Symbol.iterator 属性的对象

    思考

    这部分内容希望你都可以手动敲一遍,独立思考

    1. let map = new Map([
    2. ['a', '1'],
    3. ['b', '2']
    4. ])
    5. for (let a of map){
    6. console.log(a)
    7. }

    上面代码的输出结果会是什么?

    如果想要每次只输出map中每一项对应的值,应该怎么改写?


    试着根据上面描述的for … of实现方法,自己动手实现一个具有for … of功能的function

    接收一个可遍历对象,并向命令行依次输出遍历结果