【问题标题】:How can a Javascript object become iterable with for...of statement? [duplicate]Javascript 对象如何通过 for...of 语句变得可迭代? [复制]
【发布时间】:2016-06-19 14:06:39
【问题描述】:

我想设置options[Symbol.iterator] 属性,以便迭代我使用for...of 语句创建的简单对象:

options = {
  male: 'John',
  female: 'Gina',
  rel: 'Love'
};


for(let p of options){
  console.log(`Property ${p}`);
};

但是这段代码给了我以下错误:

 array.html:72 Uncaught TypeError: options[Symbol.iterator] is not a function

如何在上面的简单对象上设置正确的迭代器函数?

解决了

 // define the Iterator for the options object 
 options[Symbol.iterator] = function(){

     // get the properties of the object 
     let properties = Object.keys(this);
     let count = 0;
     // set to true when the loop is done 
     isDone = false;

     // define the next method, need for iterator 
     let next = () => {
        // control on last property reach 
        if(count >= properties.length){
           isDone = true;
        }
        return {done:isDone, value: this[properties[count++]]};
     }

     // return the next method used to iterate 
     return {next};
  };

我现在可以在我的对象上使用for...of 语句可迭代:

 for(let property of options){
   console.log(`Properties -> ${property}`);
 }

【问题讨论】:

  • 要使用for...of 循环,集合必须具有[Symbol.iterator] 属性。对象字面量没有这样的属性,只有数组、集合、映射等有
  • 您想为此使用Map

标签: javascript debugging ecmascript-6 iterator for-of-loop


【解决方案1】:

要使用for...of 循环,您应该使用[Symbol.iterator] 键为您的对象定义一个适当的迭代器。

这是一种可能的实现方式:

let options = {
  male: 'John',
  female: 'Gina',
  rel: 'Love',
  [Symbol.iterator]: function * () {
    for (let key in this) {
      yield [key, this[key]] // yield [key, value] pair
    }
  }
}

不过,在大多数情况下,最好使用普通的 for...in 循环来迭代对象。

或者,您可以使用 Object.keysObject.valuesObject.entries (ES7) 将对象转换为可迭代数组。

【讨论】:

  • 你真的应该做[Symbol.iterator]() { return Object.entries(this) }(除了在ES6中没有Object.entries
  • @Bergi 不,它不起作用。您必须返回一个迭代器,而不是一个可迭代的对象。要重用来自Object.entries 的迭代器,您应该return Object.entries(this)[Symbol.iterator]()
  • 哎呀,我完全忘记了Object.entries 是 ES7 草案而不是 ES6 的一部分。
  • @Bergi noop, Object.entries 返回一个由 [key, value] 对组成的普通 JS 数组。
  • 这是我实现它的方式:for (let value of Object.values(this)) yield value
【解决方案2】:

如果不想使用生成器语法,可以使用另一种方式定义迭代器函数。

    var options = {
        male: 'John',
        female: 'Gina',
        rel: 'Love',
        [Symbol.iterator]: function () {
            var self = this;
            var values = Object.keys(this);
            var i = 0;
            return {
                next: function () {
                    return {
                        value: self[values[i++]],
                        done: i >= values.length
                    }
                }
            }
        }
    };

    for (var p of options) {
        console.log(`Property ${p}`);
    }

【讨论】:

  • 我喜欢这个答案,因为与生成器方法不同,此选项允许您使用所需的任何键返回对象(与仅返回“值”和“完成”相反)例如,您可以返回一个带有 'key':values[i++] 的对象。
【解决方案3】:

普通对象(在这种情况下为options)在 ES6 中不可迭代。您需要为您的对象定义一个迭代器或执行以下操作:

for(let k of Object.keys(options)) {
  console.log(`Property ${k}, ${options[k]}`);
};

【讨论】:

  • ES6 中没有Object.entries
  • @Bergi,谢谢!很高兴知道他们将它带回 ES7。
  • @hallucinations:它们也不会成为 ES7 的一部分。最有可能是 ES8。
  • @FelixKling 我看到了this proposal,还以为是!
猜你喜欢
  • 2012-01-14
  • 2018-03-19
  • 2019-12-08
  • 2017-10-21
  • 2016-01-19
  • 2013-03-07
  • 2017-02-08
  • 1970-01-01
  • 2019-12-20
相关资源
最近更新 更多