iterator

Iterator

iterator遍历器

JS中内置了两种遍历方式forfor...in

ES6中新增了for...of语句,该语句将会根据Iterator的自定义遍历逻辑对数据进行遍历

只有在具备遍历器接口的数据上可以使用for…of(数组。类数组对象天生就有遍历器接口)

var arr = [1, 2, 3, 4];

//遍历数组中的index
for (var some in arr) {
    console.log(some);
}

//遍历数组中的value
for (var some of arr) {
    console.log(some);
}

对象不具备遍历性,给对象添加可遍历属性

遍历器接口就是引用数据类型的一个属性(方法)——该方法决定了以什么样的方式进行遍历

Iterator的作用:

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

遍历器对象遍历过程:

  1. 创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
  2. 第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。
  3. 第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。
  4. 不断调用指针对象的next方法,直到它指向数据结构的结束位置。

手写遍历器接口

遍历器结构

  • 遍历器接口返回一个遍历器对象
  • 接口是一个函数,函数返回一个遍历器对象
  • 遍历器对象必须具有next的方法
  • next方法必须返回两个东西——(value属性以及done)
  • 遍历器接口不能用symbol方法来生成,必须使用symbol.iterator来生成,特殊的值,把他做成了symbol的静态属性;也就是说所有的遍历器接口的key必须是symbol.iterator

以下为结构

 o[Symbol.iterator] = function() {
     // 遍历器对象,该对象必须拥有next方法
     // 该方法必须返回一个具备value和done属性的对象
     // 以上两点是强制要求
     return {
         next: function() {
             return {value: "", done: false}
         }
     }
 }
 <script>
     let o = {
         name: "Tom",
         age: 18,
         gender: "male"
     }

o[Symbol.iterator] = function() {
    // 获取对象o中的key,并放入数组中
    var keys = Object.getOwnPropertyNames(this);
    // ["name", "age", "gender"]
    // 想依次获取每一个key
    var index = 0;
    var self = this;

    return {
        next: function() {
            // 获取完一次key,index就++一次
            // done表示当前遍历是否完成
            var value = self[keys[index++]]
            //done: true; 遍历会立马停下来,并且前面的value就会被舍弃
            //即 for...of 只保留done为false的value
            return {value: value, done: index === keys.length && true}
        }
    }
}

for (var some of o) {
    console.log(some);
}
</script>

原理

  1. for...of第一件事就是找有没有symbol.iterator
  2. 如果有symbol.iterator就说明有遍历器接口
  3. 只要有接口,立马调用symbol.iterator,返回遍历器对象
  4. 然后就会一次一次的调用next方法
  5. 遍历器对象有什么用呢?
    • 先生成遍历器对象
    • 然后开始调用next的方法,即函数执行
    • 函数执行后,返回的值里面的value要赋值给some
    • 然后根据done属性进行判断遍历是否完成

原理精简版

  1. 先查看是否具备遍历器接口,如果有则调用接口并返回遍历器对象,反之报错
  2. 调用遍历器对象中的next方法,将该方法返回的对象中的value赋值给目标变量,根据返回的对象的done属性来决定是否进行下次遍历
  3. for...of只保留donefalsevalue

for...of遍历出什么由自己决定,只要看返回的value是什么

为什么对象不具备遍历器接口?因为对象的key是没有规律的

类数组对象使用for...of

借用array里的
<script>
        var arrLike = {
            0: "a",
            1: "b",
            2: "c",
            length: 3
        }

        arrLike[Symbol.iterator] = Array.prototype[Symbol.iterator];

        for (var some of o) {
            console.log(some);
        }
    </script>
原生类数组遍历器接口
<script>
        var arrLike = {
            0: "a",
            1: "b",
            2: "c",
            length: 3
        }

        arrLike[Symbol.iterator] = function() {
            // 为了判断什么时候遍历结束
            let len = this.length;
            // 为了获取对象中的元素
            var self = this;
            // 循环初始条件
            var index = 0
            return {
                next: function() {
                    var value = self[index++];
                    return {value: value, done: index > len && true}
                }
            }
        }

        for (var some of arrLike) {
            console.log(some);
        }
    </script>
遍历类数组对象的偶数项
<script>
        var arrLike = {
            0: "a",
            1: "b",
            2: "c",
            length: 3
        }

        arrLike[Symbol.iterator] = function() {
            // 为了判断什么时候遍历结束
            let len = this.length;
            // 为了获取对象中的元素
            var self = this;
            // 循环初始条件
            var index = 0
            return {
                next: function() {     
                    var value = self[index];
                    index+=2;
                    return {value: value, done: index > (len+2) && true}
                }
            }
        }

        for (var some of arrLike) {
            console.log(some);
        }
    </script>

Array.form依赖遍历器接口

  • Array.from可以把拥有遍历器接口的对象或者是类数组对象转换成数组
  • 把每次遍历的value放入到新数组中——遍历器对象返回什么,新数组中就是什么
  • 类数组对象又具备遍历器接口,以遍历器返回的值为准
  • Array.from是根据对象中的length进行操作
类似数组对象转数组
<script>
    var arrLike = {
        0: "Tom",
        1: "Jerry",
        2: "Tim",
        3: "Tony",
        length: 4
    }

console.log(Array.from(arrLike));
//Array(4) [ "Tom", "Jerry", "Tim", "Tony" ]
</script>
具有遍历器接口的对象转数组
var obj = {
    0: "Tom",
    1: "Jerry",
    2: "Tim",
    3: "Tony"
}

obj[Symbol.iterator] = function() {
    var keys = Object.getOwnPropertyNames(this);
    var index = 0;
    var self = this;
    return {
        next: function() {
            var value = self[keys[index++]];
            var done = index > keys.length && true
            // 属性值与属性名相同时,es6对象语法糖
            return {value, done}
        }
    }
}

var res = Array.from(obj);
console.log(res);
具有遍历器接口的类数组对象
var arrLike = {
            0: "Tom",
            1: "Jerry",
            2: "Tim",
            3: "Tony",
            length: 4
        }

//遍历偶数的key
arrLike[Symbol.iterator] = function() {
    var keys = Object.getOwnPropertyNames(this);
    var index = -2;
    var self = this;
    return {
        next: function() {
            var value = keys[index+=2];
            var done = index > keys.length && true
            // 属性值与属性名相同时,es6对象语法糖
            return {value, done}
        }
    }
}

var res = Array.from(arrLike);
console.log(res);

原生Array.form

先看有没有遍历器接口

如果没有,再看有没有length,再根据length进行for循环进行遍历

Array.from1 = function(any){
    let temp = [];
    if(any[Symbol.iterator]){
        for(let some of any){
            temp.push(some);
        }
    }else if(any.length){
        for(let i = 0; i < any.length; i++){
            temp.push(any[i]);
        }
    }
    return temp;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值