ES6: create class with .next() 属性 (iterationg 属性 字段值)

ES6: create class with .next() property (iterationg property field value)

假设我有一个名为 Frame 的 class:

class Frame {
  constructor({height, width, offset_x, offset_y}) {
    this.params = { height: height, width: width };
    this.offset = { x: offset_x, y: offset_y };
  }
  // ..getters here
}

我想要一个名为 .next() 的方法,它允许我在每次调用它时跨过偏移量。例如:

const TestFrame = new Frame({ height: 10, width: 20, offset_x: 100, offset_y: 100})
const NextFrame = TestFrame.next()
console.log(NextFrame) 
/**
 * Should give me ( ...{offset_y: 110, offset_x: 120})
 * so the new offset_y = offset_y (100) + height (10)
 * and the offset_x = offset_x (100) + width (20)
 *
 */

我听说过 yieldgenerators 但不知何故我无法通过 getters 实现它。因此,我将不胜感激您给我的任何建议或示例。

我尝试了什么:

class Frame {
  constructor({height, width, offset_x, offset_y}) {
    this.params = { height: height, width: width };
    this.offset = { x: offset_x, y: offset_y };
  }
  get next() {
    return new Frame({
      height: this.params.height,
      width: this.params.width,
      offset_x: this.offset.x,
      offset_y: this.offset.y + this.params.height
    })
  }
}

const Test = new Frame({ height: 20, width: 10, offset_x: 100, offset_y: 100 });
console.log(Test)
console.log(Test.next); //Frame { params: { height: 20, width: 10 }, offset: { x: 100, y: 120 } }
console.log(Test.next); //FIXME Frame { params: { height: 20, width: 10 }, offset: { x: 100, y: 120} } but should be ...y: 140

您可以在每次读取 next 时创建一个新框架,并跟踪创建的框架数。这将允许您在每次读取时应用一个不断进步的偏移量:

class Frame {
  constructor({height, width, offset_x, offset_y}) {
    this.params = { height: height, width: width };
    this.offset = { x: offset_x, y: offset_y };
    this.offsetCount = 0;
  }
  get center() {
    return { center: { x: (this.params.width - (this.params.width / 2)), y: (this.params.height - (this.params.height / 2)) } };
  }
  get next() {
    this.offsetCount++;
    return new Frame({
      height: this.params.height,
      width: this.params.width,
      offset_x: this.offset.x,
      offset_y: this.offset.y + (this.params.height * this.offsetCount)
    })
  }
}

const CharacterSelect = new Frame({ height: 20, width: 10, offset_x: 100, offset_y: 100 });
console.log(CharacterSelect)
console.log(CharacterSelect.next) //Frame { params: { height: 20, width: 10 }, offset: { x: 100, y: 120 } }
console.log(CharacterSelect.next) //Frame { params: { height: 20, width: 10 }, offset: { x: 100, y: 140 } }

我建议另一种方法 - 使用生成器函数来生成带偏移量的无限帧。这使您的 Frame class 无需跟踪所有内容。

class Frame {
  constructor({height, width, offset_x, offset_y}) {
    this.params = { height: height, width: width };
    this.offset = { x: offset_x, y: offset_y };
  }
  get center() {
    return { center: { x: (this.params.width - (this.params.width / 2)), y: (this.params.height - (this.params.height / 2)) } };
  }
}
const CharacterSelect = new Frame({ height: 20, width: 10, offset_x: 100, offset_y: 100 });
const frameGenerator = moreFrames(CharacterSelect);
console.log(CharacterSelect)
console.log(frameGenerator.next().value) //Frame { params: { height: 20, width: 10 }, offset: { x: 100, y: 120 } }
console.log(frameGenerator.next().value) //Frame { params: { height: 20, width: 10 }, offset: { x: 100, y: 140 } }

function* moreFrames(frame) {
  while(true) {
    const nextFrame = new Frame({
      height: frame.params.height,
      width: frame.params.width,
      offset_x: frame.offset.x,
      offset_y: frame.offset.y + frame.params.height
    });
    yield nextFrame;
    frame = nextFrame;
  }
}

使用小助手,您只能从任何可迭代对象中获取有限数量的项目:

function* limit(number, iterable) {
  const it = iterable[Symbol.iterator]();
  
  for(let i = 0, next = it.next();
      i < number && !next.done;
      i++, next = it.next()
  ) {
    yield next.value;
  }  
}

这意味着您一次只能拍摄任意数量的帧:

class Frame {
  constructor({height, width, offset_x, offset_y}) {
    this.params = { height: height, width: width };
    this.offset = { x: offset_x, y: offset_y };
  }
  get center() {
    return { center: { x: (this.params.width - (this.params.width / 2)), y: (this.params.height - (this.params.height / 2)) } };
  }
}

const CharacterSelect = new Frame({ height: 20, width: 10, offset_x: 100, offset_y: 100 });
const frameGenerator = moreFrames(CharacterSelect);

const first3 = [...limit(3, frameGenerator)];
const next5  = [...limit(5, frameGenerator)];

console.log(first3);
console.log(next5);

function* moreFrames(frame) {
  while(true) {
    const nextFrame = new Frame({
      height: frame.params.height,
      width: frame.params.width,
      offset_x: frame.offset.x,
      offset_y: frame.offset.y + frame.params.height
    });
    yield nextFrame;
    frame = nextFrame;
  }
}

function* limit(number, iterable) {
  const it = iterable[Symbol.iterator]();
  
  for(let i = 0, next = it.next();
      i < number && !next.done;
      i++, next = it.next()
  ) {
    yield next.value;
  }  
}