ES6-iterator和for...of循环

iterator的基本介绍

概念

iterator(遍历器) 是一种接口,为不同的数据结构提供统一的访问机制。
任何数据结构只要部署了iterator接口,就可以完成遍历操作

作用

  • 为各种数据结构, 提供一个统一的、简便的访问接口
  • 使得数据结构的成员能够按照某种次序排列
  • ES6创建了一种新的遍历命令 for ... of循环, iterator接口主要供 for ... of消费

遍历器对象的属性

  • next()方法: 必须部署,用于进行数据结构的遍历, 返回包含valuedone的对象
  • return()方法: 可选, 循环中断或出错时会调用, 必须返回一个对象
  • throw()方法: 可选, 配合Generator函数使用, 一般用不到

遍历过程

  • 创建一个指针对象(包含next方法), 指向当前数据结构的起始位置
  • 第一次调用指针对象的 next 方法, 将指针指向数据结构的第一个成员
  • 第二次调用指针对象的 next 方法, 将指针指向数据结构的第二个成员
  • 不断调用指针对象的 next 方法, 直到指向数据结构的结束位置

每次调用next方法, 都会返回数据结构当前成员的信息, 信息的本质是一个对象, 其中包含了valuedone两个属性:
value 属性是当前成员的值, done 属性代表遍历是否结束 Boolean 类型
如果 done 的值为 false, 那么可以只返回 value 属性
如果 value 的值为 undefined, 那么可以只返回 done 属性

原生用于iterator接口的数据

Array Arguments String Set Map NodeList

默认调用iterator接口的场合

  • 解构赋值
  • 拓展运算符(…)
  • yield* 后面跟的是一个可遍历的结构, 它会调用该结构的遍历器接口
  • 数组的遍历都会调用遍历器接口

基础示例

var arr = [
    'EcmaScript',
    'NodeJs',
    'TypeScipt',
    'uni-app',
    'vue',
]
var it = arr[Symbol.iterator]() // 得到包含next方法的指针对象
console.log(it.next()) // {value: "EcmaScript", done: false}
console.log(it.next()) // {value: "NodeJs", done: false}
console.log(it.next()) // {value: "TypeScipt", done: false}
console.log(it.next()) // {value: "uni-app", done: false}
console.log(it.next()) // {value: "vue", done: false}
console.log(it.next()) // {value: undefined, done: true} 遍历结束 value的值为undefined done的值为true

自定义部署iterator接口

默认的Iterator接口部署在数据结构的Symbol.iterator属性
或者说,一个数据结构只要具有Symbol.iterator属性,就可以认为是"可遍历的"(iterable)

普通对象

var web = {
    name : '前端',
    ctn : [
        'EcmaScript',
        'NodeJs',
        'TypeScipt',
        'uni-app',
        'vue',
    ],
    [Symbol.iterator]() {
        let index = 0
        let _this = this
        return {
            next : function () {
                if (index < _this.ctn.length) {
                    const result = {
                        value: _this.ctn[index],
                        done: false
                    }
                    index ++
                    return result
                } 
                else {
                    return {
                        value : undefined,
                        done: true
                    }
                }
            }
        }
    }
}
for (let item of web) {
    console.log(item) // EcmaScript NodeJs TypeScipt uni-app vue
}

类数组对象

类数组对象(存在数值键名length属性),部署Iterator接口,有一个简便方法,就是Symbol.iterator方法直接引用数组的Iterator接口
for...of遍历此类对象时, 只能遍历数值键名, 无法遍历字符串键名

var obj = {
    0: 'a',
    1: 'b',
    2: 'c',
    a: 111,
    length: 3,
    [Symbol.iterator] : Array.prototype[Symbol.iterator]
}
for (let item of obj) {
    console.log(item) // a b c
}

类部署iterator接口的实例

class RangeIterator {
    constructor(start, stop) {
        this.start = start
        this.stop = stop
    }

    [Symbol.iterator] () {
        return this
    }

    next() {
        var start = this.start
        if (this.start <= this.stop) {
            this.start += 1
            return {
                value: start,
                done: false
            }
        } else {
            return {
                value: undefined,
                done: true
            }
        }
    }
}
var rangeIterator = new RangeIterator(1, 3)
var it = rangeIterator[Symbol.iterator]()
console.log(it.next()) // {value: 1, done: false}
console.log(it.next()) // {value: 2, done: false}
console.log(it.next()) // {value: 3, done: false}
console.log(it.next()) // {value: undefined, done: true}

遍历器实现指针结构

function Obj(value) {
    this.value = value
    this.next = null
}

Obj.prototype[Symbol.iterator] = function () {
    var current = this

    function next () {
        if (current) {
            var value = current.value
            current = current.next
            return {
                value: value,
                done: false
            }
        } else {
            return {
                value: undefined,
                done: true
            }
        }
    }

    return {
        next : next
    }
}

var one = new Obj(1)
var two = new Obj(2)
var three = new Obj(3)
one.next = two
two.next = three

var it = one[Symbol.iterator]()
console.log(it.next()) // {value: 1, done: false}
console.log(it.next()) // {value: 2, done: false}
console.log(it.next()) // {value: 3, done: false}
console.log(it.next()) // {value: undefined, done: true}

for…in和for…of

  • for...in循环遍历得到的是数据结构的键名 for...of循环得到遍历的是数据结构的键值
  • for...in循环主要是为遍历对象而设计的, 不适用于遍历数组

for…in循环的几个缺点

  • for...in循环遍历数组时, 得到的键名的类型是string类型, 而数组的键名是number类型
  • for...in循环不仅遍历数字键名, 还会遍历手动添加的其他键, 甚至包括原型链上的键名
  • 某些情况下, for...in循环会以任意顺序遍历键名
var obj = {
    0 : 'a',
    1 : 'b',
    2 : 'c',
    length: 3,
    [Symbol.iterator] : Array.prototype[Symbol.iterator]
}
obj.foo = '123'

for(let prop in obj) {
    console.log(prop) // 0 1 2 length foo
}
for(let item of obj) {
    console.log(item) // 0 1 2
}

for…of循环的几个优点

  • 有着同for...in一样的简洁语法, 但是没有for...in那些缺点
  • 不同用于forEach方法, 它可以与breakcontinuereturn配合使用
  • 提供了遍历所有数据结构的统一操作接口。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值