首页 > 解决方案 > 扩展运算符如何使用 Javascript 中的迭代器/生成器从对象中获取值?

问题描述

我有以下一段代码定义了一个数组,然后一个带有生成器的迭代器对象从这个数组中产生值,然后我用扩展运算符输出每个值:

const arr = ['0', '1', '4', 'a', '9'];
const my_obj = {
  [Symbol.iterator]: function*() {
    for(let index of arr) {
      yield `${index}`;
    }
  }
};

const all = [...my_obj] 

console.log(...my_obj)

结果是:

0
1
4
a
9

我不明白的是,如果“my_obj”是一个对象,而不是一个数组,则扩展运算符变量“...my_obj”如何获取数组的值。据我了解:“my_obj”正在接收一个对象,如果您应用扩展运算符,它应该得到“key:value”。

有人可以解释它是如何获得这些值的吗?

标签: javascriptiteratorgeneratorspread

解决方案


扩展运算符和for...of语句调用对象的可迭代协议。一些对象,如Array, String,SetMap内置了可迭代的协议。这意味着他们有@@iterator方法。

您自己刚刚创建了一个对象并为其赋予了[Symbol.iterator]. 现在你的对象知道当for...of在这个对象上调用扩展语法时要做什么,也就是调用这个迭代器并循环一个由[Symbol.iterator]键中的生成器函数创建的可迭代对象。

并且在您的生成器函数中,您已经指定在每次迭代中arr都应该产生一个值,直到该循环完成。

MDN在这里展示了一个例子,它说:

一些内置结构(例如扩展语法)在底层使用相同的迭代协议: console.log([...someString]); // ["h", "i"]

有时你会看到一个模式是一个对象有一个values方法。大多数时候,这实际上是一个生成器函数。当[Symbol.iterator]调用它时,它返回生成器函数,然后循环对象中的值。

在这里,我创建了一个小演示,它接收一个字符串并循环遍历字母并使用扩展for...of运算符将它们布局。将调用一个生成器函数来查找每个字母在字母表中的位置。两者都使用相同的可迭代协议。[Symbol.iterator]

class LettersObjects {

  *values() {
    // Here we use the iterable protocol of a string.
    for (const letter of this.letters) {
      const position = this.alphabet.indexOf(letter.toLowerCase()) + 1;
      yield position.toString().padStart(2, '0');
    }
  }

  // This is called with for...of and ...spread.
  [Symbol.iterator]() {
    return this.values();
  }
  
  constructor(letters) {
    this.letters = letters;
    this.alphabet = 'abcdefghijklmnopqrstuvwxyz';
  }
  
}

const letters = new LettersObjects('Hello world');

// Call the iterable protocol on our LetterObjects instance.
for (const letter of letters) {
  console.log('loop:', letter);
}

// Call the iterable protocol on our LetterObjects instance.
console.log('Spread:', ...letters);


推荐阅读