关闭克隆可更新原始对象

时间:2018-07-15 22:06:16

标签: javascript ecmascript-6

我正在尝试克隆电路板,因为每次我运行minMax时,我的minMax函数都需要一个当前电路板状态的副本。

我最近将es6 Board.js模块从单例转换为(从中导出函数)到闭包(返回函数的函数,因为我想隐藏状态,并且还利用了能够调用函数工厂来创建函数的优势)新的董事会实例。

所以现在Board.js看起来像这样:

Board.js

function Board() {
  let board = [
    ' ', ' ', ' ',
    ' ', ' ', ' ',
    ' ', ' ', ' '];

  function slotIsOpen(position){
    const open = board[position] === ' ';
    return open;
  }

  function getOpenSlots(){
    const openSlots = board.filter((slot) => {
      return slot === ' '
    });
    return openSlots;
  }

  function getBoard() {
    return board;
  }

  function isFull(board){
    const emptySlots = board.filter(slot => { return slot === ' '});
    return emptySlots.length === 0;
  }

  function addMoveToBoard(position, player){
    board.splice(+position, 1, player.marker);
  }

  const api = {
    addMoveToBoard,
    isFull,
    getBoard,
    getOpenSlots,
    slotIsOpen
  };

  return api;
}

export default Board;

我的 Player.js ,它带有Board()实例:

function Player(board, ai){

  async function move({position = -1, currentPlayer = null}){
    const minMaxBoard = Object.create(board),
      nextMove = await ai.minMax(minMaxBoard, currentPlayer)

    if(nextMove){
      const moved = Move.makeMove(nextMove.openSpaceIndex, currentPlayer, board);
      return moved;
    }
  }

  const player = {
    addPlayer
  };

  return player;
}

export default Player

这是怎么回事:

const minMaxBoard = Object.create(board)-我创建了板工厂的克隆(或者我认为),然后将其作为Board()的副本发送到我的minMax函数中。 (请牢记board中的Player(board, ai)是我注入Player的参数。调用方只是在Board()中发送该参数)。

我的minMax函数利用该副本,操纵它进行一些分析。该副本还是木板的副本,因此无论当前木板的状态如何,它都可以使用,而不会影响原始木板。

完成minMax之后,我的makeMove被称为: const moved = Move.makeMove(nextMove.index, currentPlayer, board);

问题是这里的board应该与发送到Player的原始板一起使用。但是我注意到它以某种方式丢失了该引用,现在正在引用minMaxBoard。为什么?

我也尝试了const minMaxBoard = Board();而不是const minMaxBoard = Object.create(board);,但是这会导致一个问题..那就是minMax函数最终会得到一个全新的空板...这不是什么我想发送到minMax中。我想要发送的当前板的副本具有当前状态。

更新

我已经对其进行了更改,以尝试提供克隆功能,但仍无法正常工作,每次调用克隆时,我仍然会得到一个新的空白板:

function _Board(board) {
  function slotIsOpen(position){
    const open = board[position] === EMPTY_CELL;
    return open;
  }

  function getOpenSlots(){
    const openSlots = board.filter((slot) => {
      return slot === EMPTY_CELL
    });
    return openSlots;
  }

  function getBoard() {
    return board;
  }

  function isFull(board){
    const emptySlots = board.filter(slot => { return slot === EMPTY_CELL});
    return emptySlots.length === 0;
  }

  function addMoveToBoard(position, marker){
    board.splice(position, 1, marker);
  }

  function clone() {
    return Board(board.slice());
  }

  return {
    addMoveToBoard,
    clone,
    isFull,
    getBoard,
    getOpenSlots,
    slotIsOpen
  };
}

function Board() {
  return _Board([
    ' ', ' ', ' ',
    ' ', ' ', ' ',
    ' ', ' ', ' ']);
}

export default Board;

然后在 Player.js 中:

const minMaxBoard = board.clone();
const nextMove = await ai.minMax(minMaxBoard, currentPlayer)

但我仍然遇到相同的问题,即克隆每次都以空板结尾,而不是board的当前状态副本,board仍然是实例{ {1}}发送到Board()

我也尝试了Player,但是仍然没有在新的Board中获得当前Board阵列的副本。

1 个答案:

答案 0 :(得分:0)

Object.create不会克隆传递给它的对象-而是创建一个新的对象,其内部 prototype 是传递的对象。如果您随后继续引用(并可能变异)恰好在 prototype 上的属性,那么确实会变异原始原型。

如果要拥有Board的多个独立副本,则每次都需要显式调用Board(),例如:

function Player(board, ai){
  async function move({position = -1, currentPlayer = null}){
    // Create an entirely new Board:
    const minMaxBoard = Board();

要制作现有电路板的副本,您可能需要Board接受board数组的参数才能使用:

const defaultBoard = [
  ' ', ' ', ' ',
  ' ', ' ', ' ',
  ' ', ' ', ' '];
function Board(board = defaultBoard) {
  // ...

// other file:

function Player(board, ai){
  async function move({position = -1, currentPlayer = null}){
    const minMaxBoard = Board(board.getBoard().slice());