在Javascript生成器函数中设置键

时间:2017-08-21 22:43:10

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

您好我想弄清楚如何在符号迭代器中设置密钥,这是我到目前为止的代码:

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

3 个答案:

答案 0 :(得分:3)

如果要同时生成键和值,则需要生成包含两个项的数组,例如

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};
    },
  };
};

但是它不再是迭代器了,它只是你自己定义的一个自定义的东西。

答案 1 :(得分:2)

你无法做到。 ES6中迭代器的接口是不可更改的:

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

发电机只能使用它。无论你产生什么,它都会在value

答案 2 :(得分:1)

我修改了@ jack.the.ripper代码以使用Object.keys,然后修改了箭头函数,所以我们可以使用它。

let buttons = document.getElementById("show-cart");
buttons.addEventListener("click", function (event) {
    let name = event.target.getAttribute("data-name");
    if (event.target.className === "delete") {
        removeItemFromCartAll(name);
        displayCart();
    } else if (event.target.className === "minus") {
        removeItemFromCart(name);
        displayCart();
    } else if (event.target.className === "plus") {
        addItemToCart(name, 0, 1);
        displayCart();
    }
});