美文网首页
迭代器的相关概念以及自定义一个迭代器

迭代器的相关概念以及自定义一个迭代器

作者: BIGHAI | 来源:发表于2017-05-28 10:55 被阅读0次

    Object.keys()会返回一个数组,包含所有可枚举属性;Object.getOwnPropertyNames()会返回一个数组,包含所有的属性,无论他们是否可枚举;对于Object.keys()和Object.getOwnPropertyNames()来说,他们都不会涉及到[[Prototype]]原型链上的属性。in和hasOwnProperty()的区别在于是否查找[[Prototype]]链,in操作符会检查属性是否在对象以及[[Prototype]]原型链上;hasOwnProperty()只会检查属性是否在对象中,并不会检查[[Prototype]]链。所有的对象都可以通过Object.prototype委托来访问hasOwnProperty(),但是有的对象可能没有连接到Object.prototype(比如说通过Object.create()创建的对象),在这种情况下,调用hasOwnProperty()就会失败。这时通过call等方法就可以解决这个问题。

    如果某种数据类型的对象能够使用for...of...遍历的话,那是因为这种数据类型实现了迭代器。当然,对于普通的对象来说,它没有内置的迭代器,所以我们不能使用for...of...来进行遍历工作。不过,我们可以为其自定义一个迭代器。

    var obj = {
      "key1": 1,
      "key2": 2
    }
    Object.defineProperty(obj, Symbol.iterator, {
      "writable": false,
      "enumerable": false,
      "configurable": true,
      "value": function(){
         var index = 0
         var target = this
         var targetKeys = Object.keys(target)
         return {
            "next": function(){
                return {
                  "value": target[targetKeys[index++]],
                  "done": (index > targetKeys.length)
                }
             }
         }
      }
    })
    for(var value of obj){
      console.log(value)//1 2
    }
    

    1.写一个无限迭代器
    无限迭代器的思想就是done属性的值总是为假。

    var obj = {
      [Symbol.iterator]: function(){
        var times = 0
        return {
          "next": function(){
            return {
              "value": times++,
              "done": false
            }
          }
        }
      }
    }
    for(var time of obj){
      console.log(time)
    }
    

    2.需要注意的地方
    先看一个例子:

    var arr = [1, 2, 3, 4, 5]
    Array.prototype[Symbol.iterator] = function(){
      const target = this
      var index = 0
      return {
        "next": function(){
           return index < target.length ? {"value": target[index++]+1, "done": false} : {"value": undefined, "done": true}
        }
      }
    }
    arr.forEach((value, index) => {console.log(value)})//1 2 3 4 5
    for(var num of arr){console.log(num)}//2 3 4 5 6
    

    从上面那个例子,我们可以看出forEach遍历循环并不会使用iterator迭代器,它使用的遍历只是采用的常规的方法。
    上面那个例子还有一个隐患,那就是我们为了改造arr的迭代器进而把数组的内置迭代器给修改了,这是会对工程中的后续代码造成隐患的——后续的数组类型对象的迭代器都被相应的改变。这同时也揭露了这么一个特性:对于数组对象来说,他的迭代器方法并不是存在数组对象自身里面的,而是存在于数组对象的[[Prototype]]上的这个对象——即Array.prototype中。同时也要注意这一点的其他应用:在对象上直接定义一个迭代器会把对象构造函数的prototype对象上的构造器给覆盖掉。下面可以看一个例子:

    var arr = [1, 2, 3, 4, 5]
    Array.prototype[Symbol.iterator] = function(){
      const target = this
      var index = 0
      return {
        "next": function(){
           return index < target.length ? {"value": target[index++]+1, "done": false} : {"value": undefined, "done": true}
        }
      }
    }
    for(var num of arr){console.log(num)}//2 3 4 5 6
    console.log(arr.hasOwnProperty(Symbol.iterator))//false
    var arrPrototype = Object.getPrototypeOf(arr)
    console.log(arrPrototype.hasOwnProperty(Symbol.iterator))//true
    

    END

    相关文章

      网友评论

          本文标题:迭代器的相关概念以及自定义一个迭代器

          本文链接:https://www.haomeiwen.com/subject/okncfxtx.html