【问题标题】:Set key in a Javascript generator function在 Javascript 生成器函数中设置键
【发布时间】:2018-01-30 02:00:50
【问题描述】:

您好,我正在尝试弄清楚如何在符号迭代器中设置键,这是我目前拥有的代码:

let james = {
    name: 'James',
    height: `5'10"`,
    weight: 185
};

james[Symbol.iterator] = function* () {
    for (let key in this) {
        yield this[key];
    }
}

let iterator = james[Symbol.iterator]();
console.log(iterator.next().value); // 'James'
console.log(iterator.next().value); // `5'10`
console.log(iterator.next().value); // 185

我遇到的问题例如: iterator.next() 的调用应该打印出来

{"value": "James", "key": "name", "done": false}

但我得到了

{"value": "James", "done": false}

我想以某种方式设置“键”,就像设置“值”一样。

我查看了documentation,但我没有看到任何与此相关的文档。

有什么想法吗?

编辑

问题的用例基本上是将 James 对象 变成 可迭代对象,“如何”并不重要,所以我的第一次尝试是使用生成器,然后我意识到我需要以这种格式打印对象:

{ value: 'James', key: 'name', done: false }
{ value: '5\'10"', key: 'height', done: false }
{ value: 185, key: 'weight', done: true }

这不是标准的方法,所以我必须创建一个自定义方法来“实现”该行为:

感谢@loganfsmyth 为我指明了正确的方向,我想出了这个简单的解决方案:

let james = {
    name: 'James',
    height: `5'10"`,
    weight: 185
};

james[Symbol.iterator] = function (){
   const keys = [];
   for (let key in this) {
      keys.push({'key':key, 'value':this[key]});
    }
  return {
    next(){
      let {key,value} = keys.shift();
      return {value,key,done:keys.length===0};
    }
  }
}

let iterator = james[Symbol.iterator]();
console.log(iterator.next().value); // 'James'
console.log(iterator.next().value); // `5'10`
console.log(iterator.next().value); // 185

【问题讨论】:

  • the call to iterator.next() should print ... 为什么?迭代器显式产生 value/done 对象,你不能在那里有其他字段。

标签: javascript ecmascript-6 functional-programming iterator generator


【解决方案1】:

如果你想同时产生键和值,你需要产生一个包含两个项目的数组,例如

yield [key, this[key]];

那么对象上的.value 将是一个键/值对。

另请注意,此行为类似于您从 Object.entries(james) 获得的行为,这是 ES2017 中添加的一个新函数,只是它返回一个 Array

如果明确想要

.next()

要返回一个同时包含keyvaluedone 的对象,那么答案是您不能使用生成器来执行此操作。这不是生成器提供的 API,也不是 ES6 中定义的迭代器协议,所以你不应该使用迭代器来尝试这样做。

你当然可以

james.makeCustomThing = function(){ 
  const pairs = [];
  for (const key in this) pairs.push([key, this[key]]);
  return {
    next(){
      if (pairs.length === 0) return {done: true};

      let [key, value} = pairs.shift();
      return {key, value, done: false};
    },
  };
};

但它不再是迭代器,它只是你自己定义的自定义事物。

【讨论】:

  • 感谢您的回复,但我需要在下一个打印时拥有这个对象 => {"value":"James","key":"name","done":false}而不是嵌入的键值对
  • 但这不是迭代器的工作方式,所以你宁愿遵循标准,还是喜欢那个输出,因为你不能同时拥有两者。您也没有提供有关用例的任何信息,因此很难提供除此之外的太多指导。
  • 基本上,用例是将james对象转换为可迭代对象,“如何”并不重要,但我的第一次尝试就像使用生成器,然后我意识到,我需要要打印我之前提到的对象,我会尝试不同的方法
  • 让迭代器返回成对的项目是迭代对象的标准方法。这就是为什么所有的 ES* API 都在 .entries() 函数上实现了标准化。 .entries 存在于 ArrayObjectMapSet。您还没有说明为什么您 需要 有一个 .key 而不是一个数组。如果是因为您有时希望能够仅迭代值,则可以为这两种情况使用两种不同类型的迭代器函数。
  • @jack.the.ripper:如果你不遵守标准,那么for...ofArray.from 之类的东西就不会像你期望的那样工作。
【解决方案2】:

你做不到。 ES6 中迭代器的接口是不变的:

interface IteratorResult {
  done: boolean;
  value: any;
}
interface Iterator {
  next(): IteratorResult;
}
interface Iterable {
  [Symbol.iterator](): Iterator
}

并且生成器只能使用它。无论你产生什么,它都会在value 中。

【讨论】:

    【解决方案3】:

    我修改了@jack.the.ripper 代码以使用 Object.keys 和 next 带有箭头功能,所以我们可以使用它。

    const james = {
        name: 'James',
        height: `5'10"`,
        weight: 185
    };
    
    james[Symbol.iterator] = function (){
      const keys = Object.keys(this)
      return {
        next: () => {
          let key = keys.shift();
          return {value: this[key], key, done:keys.length===0};
        }
      }
    }
    
    let iterator = james[Symbol.iterator]();
    console.log(iterator.next().value); // 'James'
    console.log(iterator.next().value); // `5'10`
    console.log(iterator.next().value); // 185
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-04-08
      • 1970-01-01
      • 1970-01-01
      • 2021-12-28
      • 1970-01-01
      • 2017-01-17
      • 2018-02-09
      • 1970-01-01
      相关资源
      最近更新 更多