如何防止将构造对象的引用返回到分配给前目标结构的源对象之类的蓝图?

How to prevent references from a constructed object back into a blueprint like source object which got assigned to the former target structure?

这是一个类似口袋妖怪的游戏的例子。我正在构建一个对象,并在其中尝试创建一个新对象“en”和“to”,这是两种不同的攻击。问题是,当我尝试在任一攻击对象(“en”和“two”)中编辑某些内容时,每个具有相同名称的口袋妖怪都会发生变化。 “健康”不会发生这种情况,所以我认为 this.en = new Object; 是问题所在。

这是构建口袋妖怪的代码

function Fakemon(_navn, _type, _attackPower, _src,
    _1Navn, _1Force, _1Antall_, _2Navn, _2Force, _2Antall) {
    this.navn = _navn;
    this.type = _type;
    this.attackPower = _attackPower;
    this.src = _src;

    this.en = new Object;
    this.en.navn = _1Navn;
    this.en.force = _1Force;
    this.en.antall = _1Antall_;

    this.to = new Object;
    this.to.navn = _2Navn;
    this.to.force = _2Force;
    this.to.antall = _2Antall;

    this.health = 1000;

    console.log(this.en);
    this.pushFakemon = function() {
        fakemonSamling.push(this);
    }
    this.pushFakemon();
}

const fakemon1 = new Fakemon("BatCat", "Flying", [10, 50], ["batFront.png", "batBack.png"], "Blood Suck", [25, 38, 60], 10, "Wing Slap", [10, 17, 25], 20);
const fakemon2 = new Fakemon("Muffin Time", "Normal", [15, 45], ["cupcakeFront.png", "cupcakeBack.png"], "Frosting cover", [10, 17, 25], 20, "Cake stomp", [40, 50, 60], 5);

这是给每个玩家放置三个口袋妖怪的代码

for (let i = 0; i < 3; i++) {
        var temp1 = new Object;
        player1.push(Object.assign(temp1, randomFakemon()));
        var temp2 = new Object;
        player2.push(Object.assign(temp2, randomFakemon()));
    }

显然 OP has/had 有两个设计选择的问题。

player1.push(Object.assign(temp1, randomFakemon())); ...从 OP 的 fakemon 集合中随机挑选一个真实的 Fakemon 实例。

Object.assign treats the source like an ordinary object. It assigns just the source object's enumerable own properties to the target object. Thus, nested, non primitive 属性仍将保留对其来源的引用。目标对象也不会改变它的类型。它不会突然成为 Fakemon.

的实例

刚刚描述的问题可以通过 clone 函数的可靠实现来解决,或者如果可用的话,通过 structured clone.

使用克隆方法构造函数,虽然它创建自己的类型,但既不extend/subclass也不实现原型方法,因此变得无用。

OP 示例代码中唯一的(自己的)方法无论如何都是可有可无的,因此建议的解决方案是代码重构 fakemon factory函数和clone功能的使用.

function createFakemon(base, attack1, attack2) {
  const fakemon = Object.assign({
      health: 1000,
    }, base, {
      en: { ...attack1 },
      to: { ...attack2 },
    });
  fakemonCollection.push(fakemon);

  return fakemon;
};
const fakemonCollection = []; // Dansk: fakemon samling.

function getRandomFakemon() {
  return fakemonCollection[
    Math.floor(Math.random() * fakemonCollection.length)
  ];
}

const cloneDataStructure = (
  ('function' === typeof structuredClone) && structuredClone ||
  (value => JSON.parse(JSON.stringify(value)))
);

const fakemon1 = createFakemon({
  navn: 'BatCat',
  type: 'Flying',
  attackPower: [10, 50],
  sources: ['batFront.png', 'batBack.png'],
}, {
  navn: 'Blood Suck',
  force: [25, 38, 60],
  antall: 10,
}, {
  navn: 'Wing Slap',
  force: [10, 17, 25],
  antall: 20,
});
const fakemon2 = createFakemon({
  navn: 'Muffin Time',
  type: 'Normal',
  attackPower: [15, 45],
  sources: ['cupcakeFront.png', 'cupcakeBack.png'],
}, {
  navn: 'Frosting cover',
  force: [10, 17, 25],
  antall: 20,
}, {
  navn: 'Cake stomp',
  force: [40, 50, 60],
  antall: 5,
});

// create a(ny) player's fakemon as true clone
// of a randomly picked `fakemonCollection` item.
const playerFakemon = cloneDataStructure(
  getRandomFakemon()
);
// change a single attack value.
playerFakemon.en.navn = 'Foo Bar';
/*
  Thus instead of ...

  player1.push(Object.assign(temp1, randomFakemon()));

  ... one now would do ...

  player1.push(cloneDataStructure(getRandomFakemon()));
*/
console.log({
  // no mutation at any of the collection's fakemon items.  
  fakemonCollection,
  // single different value for `playerFakemon.en.navn`.
  playerFakemon,
});
.as-console-wrapper { min-height: 100%!important; top: 0; }