Не может разрушить объект внутри генератора функций - PullRequest
2 голосов
/ 05 марта 2020

Я хочу деструктурировать результат предыдущего дохода, используя значения по умолчанию, когда объект пуст. Но я получаю Невозможно прочитать свойство 'xxx' с неопределенным , что означает, что когда я пытаюсь деструктурировать переменную theObject, это не определено, но почему?

const DEFAULT_POSITION = {x: 20, y: 20}
const myObject = {}

function* myGenerator(i) {
  const theObject = yield myObject;
  const { posX = DEFAULT_POSITION.x, posY = DEFAULT_POSITION.y, scale = 1 } = theObject

  yield {posX, posY, scale}
}

Первый результат возвращает мне пустой объект, как и ожидалось, но затем, когда я снова запускаю генератор, я получаю ошибку, что первый элемент (posX) при уничтожении объекта не может быть прочитано, так как theObject не определен.

Ответы [ 2 ]

3 голосов
/ 05 марта 2020

Проблема в том, что вы yield myObject для вызывающего абонента , результат этого yield читается из вызывающего абонента через next(/* this "undefined" argument gets passed into your generator function*/) вызов. Так что theObject равно undefined, потому что вы не используете генератор по назначению.

Когда вызывается метод next () итератора, тело функции генератора выполняется до первого выражения yield, который указывает значение, которое будет возвращено из итератора

Вызов метода next () с аргументом возобновит выполнение функции генератора, заменив выражение yield, где выполнение было приостановлено, аргументом из next ()

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*

Это не очень интуитивно понятно, функции генератора такие странные.

Следующее работает, но, вероятно, не то, что вам нужно насколько я понимаю

const DEFAULT_POSITION = {x: 20, y: 20}
const myObject = {}

function* myGenerator(i) {
  const theObject = yield
  const { posX = DEFAULT_POSITION.x, posY = DEFAULT_POSITION.y, scale = 1 } = theObject

  yield {posX, posY, scale}
}
const it = myGenerator()
console.log(it.next()) // -> {value: undefined, done: false}
console.log(it.next(myObject)) // -> {value: { posX: 20, posY: 20, scale: 1 }, done: false}
0 голосов
/ 05 марта 2020

Понимание генератора

Один из способов восприятия yield - это точка останова, которая возвращает значение вызывающему телу. Он также может передавать значение в теле генератора, но значение должно быть передано с использованием next(), как описано в MDN: Генератор # следующий :

в variable = yield expression значение, переданное в функцию .next(), будет присвоено переменной.

В вашем случае значение не передается в next() (по крайней мере, не в данном коде), поэтому theObject равен undefined, и возникла ошибка при использовании в назначении реструктуризации.

Я попытался переделать ваш код в двух примерах, с / без аргумента, переданного ему для инициализации, а затем с некоторым циклом, чтобы продемонстрировать использование предыдущего значения.


Аргументы не переданы в генератор

Следующие аргументы не передаются в функцию генератора. Несколько выходов предназначены для демонстрации возвращаемого значения из генератора.

function* GetPositions(args={}) {
  const defaults = {x:20,y:20}
  const position = Object.assign({}, defaults, args)
  yield position             // return initial setup
  
  const { x:posX, y:posY, scale = 1 } = position
  yield {posX, posY, scale}  // return next value
}


let coord = GetPositions()
console.log( coord.next().value )  // {x:20, y:20}
console.log( coord.next().value )  // {posX:20, posY:20, scale:1}

Передача аргументов в генератор

Следующее передает один объект в функцию генератора. Это только частичный объект, поскольку он содержит один ключ для демонстрации использования внутренних значений по умолчанию.

function* GetPositions(args={}) {
  const defaults = {x:20,y:20}
  const position = Object.assign({}, defaults, args)
  yield position             // return initial setup
  
  const { x:posX, y:posY, scale = 1 } = position
  yield {posX, posY, scale}  // return next value
}

let coord = GetPositions({x:1})   // initial argument
console.log( coord.next().value ) // {x:1, y:20}
console.log( coord.next().value ) // {posX:1, posY:20, scale:1}

Цикл в генераторе

Это было бы ближе к тому, для чего вы могли бы использовать генератор, так как чаще используется генератор в повторяющийся способ генерации последовательностей или предварительных значений.

function* GetPositions(args={}) {
  const defaults = {x:20,y:20}
  const position = Object.assign({}, defaults, args)
  let { x:posX, y:posY, scale = 1 } = position
  
  yield {posX, posY, scale}
  
  while(true){
    posX+=5, posY+=5
    yield {posX, posY, scale}     // return next value
  }
}

let coord = GetPositions({x:1})   // initial argument

console.log( coord.next().value ) // {posX:1,  posY:20, scale:1}
console.log( coord.next().value ) // {posX:6,  posY:25, scale:1}
console.log( coord.next().value ) // {posX:11, posY:30, scale:1}
...