This is an example from a Pokemon-like game. I am constructing an Object, and inside it i am trying to make a new Object "en" and "to", that is two different attacks. The problem is that when i try to edit something in either of the attack Objects ("en" and "two"), the change happens to every Pokemon with the same name. This doesn't happen with the "health", so i think that the this.en = new Object;
is the problem.
This is the code for constructing the Pokemon
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);
This is the Code for putting three Pokemon's to each player
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()));
}
Apparently the OP has/had problems with two of the design choices.
player1.push(Object.assign(temp1, randomFakemon()));
... picks a random true Fakemon
instance from the OP's fakemon collection.
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 properties still will hold references to their's sources. The target object also will not change its type. It will not all of a sudden be an instance of Fakemon
.
The just described problem can be solved with a reliable own implementation of a clone
function or, if available, by a structured clone.
With the cloning approach a constructor, though it create own types, but does neither extend/subclass nor implement prototypal methods, renders useless.
The only (own) method from the OP's example code is dispensable anyway, thus the suggested solution is a code refactoring towards a fakemon factory function and the usage of clone
functionality.
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; }