ES6之Iterator

15 篇文章 0 订阅

Iterator(遍历器)概念

  • Iterator目的

    • 为各种数据结构,提供统一的访问机制
    • 使数据结构成员,按照某种次序排列
    • 提供新的遍历命令:for…of循环
  • Iterator遍历过程

    • 创建指针对象,指向数据起始位置
    • 调用指针对象next方法,指针指向数据第一个成员,返回{value,done}对象
    • 重复步骤2,指针后移,直至数据结束位置
  • 遍历器模拟

//遍历器模拟
var it = maker()

it.next()       //{value: 0, done: false}
it.next()       //{value: 1, done: false}
it.next()       //{value: 2, done: false}

function maker() {
    var index = 0
    return {
        next() {
            return { value: index++, done: false }
        }
    }
}
  • 自定义遍历器
//自定义遍历器:执行Symbol.iterator方法,返回遍历器对象,该对象具有next方法
class RangeIterator {
    constructor(start, stop) {
        this.value = start
        this.stop = stop
    }

    [Symbol.iterator]() { return this }

    next() {
        let { value, stop } = this
        if (value < stop) {
            this.value++
            return { value }
        } else {
            return { done: true }
        }
    }
}

function range(start, end) {
    return new RangeIterator(start, end)
}
//单个输出
var it = range(1, 3)[Symbol.iterator]()
it.next()           //{value: 1}
it.next()           //{value: 2}
it.next()           //{done: true}

//for...of遍历(默认调用Symbol.iterator方法,后调用next循环)
for (let v of range(0, 5)) {
    console.log(v)          //依次输出0-4
}
  • 修改数组for…of输出
//修改数组for...of遍历,输出2倍值
var arr = [1, 2, 3]

Array.prototype[Symbol.iterator] = function () {
    let me = this
    let i = 0
    return {
        next() {
            if (i++ < me.length) {
                return { value: me[i - 1] * 2 }
            } else {
                return { done: true }
            }
        }
    }
}
var it = arr[Symbol.iterator]()
for (let v of arr) {		 //谷歌浏览器:输出2,4,6
    console.log(v)
}

默认Iterator接口

  • 使用for…of时,自动调用Iterator接口
  • 部署Iterator - “可遍历的” - Symbol.iterator属性(值为函数)
//Symbol.iterator
var obj = {
    [Symbol.iterator]() {
        return {
            index: 1,
            next() {
                return {
                    value: this.index++,
                    done: false
                }
            }
        }
    }
}
//next调用
var it = obj[Symbol.iterator]()
it.next()                   //{value: 1, done: false}
it.next()                   //{value: 2, done: false}

//for...of循环: 自动调用obj的Symbol.iterator方法,并调用next遍历
for (var i of obj) {
    console.log(i)      //输出1-9
    if (it.next().value > 10) {
        break
    }
}
  • 原生具备Iterator数据结构(Iterator在原型上)
    • Array
    • Map
    • Set
    • String
    • TypedArray
    • arguments对象
    • NodeList对象
//Array: 输出value,
var arr = [1, 2, 3]
for(let v of arr){
    console.log(v)
}


//Map: 输出key,value
var m = new Map([['a', 1], ['b', 2]])
for (let [v, k] of m) {
    console.log(k, v)
}

//Set: 输出value
var s = new Set([1, 2, 3, 1, 2, 3])
for (let v of s) {
    console.log(v)
}

//String:输出每个字符串
var str = '1231'
for (let v of str) {
    console.log(v)
}

//Arguments: 遍历参数
fun(1, 2, 3)
function fun() {
    for (let v of arguments) {
        console.log(v)
    }
}

//NodeList: 输出p元素
var eles = document.getElementsByTagName('p')
for (let v of eles) {
    console.log(v)
}
  • 原型的Iterator
//Iterator部署在原型上
arr[Symbol.iterator] === Array.prototype[Symbol.iterator]       //true

//覆盖默认Iterator
var str = '123'
String.prototype[Symbol.iterator] = () => {
    return {
        next() {
            return { a: 1 }
        }
    }
}
for (let v of str) {
    console.log(v)
}
  • 自定义Iterator接口
  • 可在原型链上部署Iterator
  • Symbol.iterator方法不是遍历器生成函数,遍历则报错
//覆盖默认Iterator:字符输出为x
var str = '123'
String.prototype[Symbol.iterator] = function () {
    let me = this
    let i = 0
    return {
        /**
         * 1. next必须返回对象格式
         * 2. 返回done为true时,遍历结束,for...of循环退出
         */
        next() {
            if (i++ < me.length) {  
                return {
                    value: 'x'
                }
            } else {                
                return {
                    done: 1
                }
            }
        }
    }
}
for (let v of str) {
    console.log(v)
}

使用场合(默认调用Symbol.iterator)

  • 解构赋值
  • 扩展运算符
    • 扩展运算符重写
var str = 'hello';
[...str]		//["h", "e", "l", "l", "o"]

//覆盖默认Iterator:字符输出为x
String.prototype[Symbol.iterator] = function () {
    let me = this
    let i = 0
    return {) {
            if (i++ < me.length) {
                return {
                    value: 'x'
                }
            } else {
                return {
                    done: 1
                }
            }
        }
    }
};

[...str]		//["x", "x", "x", "x", "x"]
  • yield*
//遍历生成器, yield*后面的可遍历结构会自动遍历
var generator = function* () {
    yield 1
    yield* '234'
    yield 5
}
for (let v of generator()) {	//依次输出1-5
    console.log(v)
}
  • 接受数组作为参数
    • for…of
    • Array.from()
    • Map,Set…
    • Promise.all…
//接受数组作为参数
Array.from([1, 2])       //[1,2]
//重写

Array.prototype[Symbol.iterator] = function* () {
    yield 'hi';
};

Array.from([1, 2])      //["hi"]
new Set([1,2])          //Set(1) {"hi"}

扩展

  • Iterator与Generator函数
// Iterator的简单实现: Generator
var it = {
    *[Symbol.iterator]() {
        yield* [1, 2, 3]
    }
};
//...和for...of均依次输出1,2,3
[...it]
for (let x of it) {
    console.log(x)
}
  • Iterator中的return/throw方法
//遍历结束(报错或break):走return
var it = {
    [Symbol.iterator]() {
        let i = 0
        return {
            next() {
                if (i > 5) {
                    return { done: 1 }
                }
                return { value: i++ }
            },
            //必须返回对象, next返回done:true后,不走return
            return() {
                console.log('return')
                return {}
            }
        }

    }
};
for (let x of it) {
    if (x++ > 3) break;
    console.log(x)          //走return
}

for (let x of it) {
    if (x++ > 8) break;
    console.log(x)          //不走return
}
  • for…of循环
    • 一个数据结构只要部署了Symbol.iterator属性,就被视为具有 iterator 接口,就可以用for…of循环遍历它的成员
  • 计算生成的数据结构(可遍历)
    • 三个对象: Array,Set,Map
    • 三个返回遍历器对象的方法:entries,keys,values
Array.prototype.entries         //f
Set.prototype.entries           //f
Map.prototype.entries           //f
Object.prototype.keys           //undefined
let map = new Map([[1, 1], [2, 2]]);
[...map.entries()]              //[Array(2), Array(2)]
  • 与其他遍历语法的比较
    • for循环:写法麻烦
    • forEach:break和return命令失效
    • for…in
      • 数组键名是字符串
      • 不仅仅遍历数字键名
      • 遍历顺序无法保证
      • 为对象遍历设计,不适用于数组
    • for…of无for…in的缺点,可以使用break等,为所有可遍历结构的统一接口
//for...in
var arr = [1,2,3]
Array.prototype.c = 'c'
arr.d = 'd'
arr.a = 'a'
//依次输出0,1,2,d,a,c
for(let k in arr){
    console.log(k)
}
//1,2,3
for(let v of arr){
    console.log(v)
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值