Ve kterém jsem si téměř nevšiml chyby
Podařilo se mi vystopovat jemnou, ale důležitou chybu, kterou jsem dělal, když jsem používal konstruktory s podtřídami a ručně nastavoval prototypy.
Zvažte následující kód (z implementace kámen-papír-nůžky):
function Player(){
this.move = null;
}
Player.prototype.setMove = function(mv) {
this.move = mv;
};
function HumanPlayer() {
}
HumanPlayer.prototype = new Player();
let player1 = new HumanPlayer();
let player2 = new HumanPlayer();
player1.setMove('paper');
console.log(player1.move, player2.move);
//paper null
I když chyba nakonec nebyla hlavním problémem, všimněte si, kde je původně uložena vlastnost move hráčů1 a hráče2 - objekt, na který odkazuje HumanPlayer.prototype
- a tento objekt je sdílen všemi HumanPlayer
objekty!
Oba hráči přistupují ke svým move
vlastnost z Human.prototype
- což znamená, že sdílejí this.move
! Potvrďte to kontrolou hodnoty move
pomocí getPrototypeOf()
console.log(player1.hasOwnProperty('move'));
//false
console.log(Object.getPrototypeOf(player1).move);
//null
Object.getPrototypeOf(player2).move = 'paper';
console.log(player1.move);
//paper
Nejen player1
nemají vlastní přesunutí vlastnosti, nastavení player2.[[Prototype]].move
na paper
k němu přistupuje player1.move
! move
ve skutečnosti nemáme definován jako individuální stav pro každou instanci HumanPlayer
Kupodivu program fungoval dobře - zvažte setMove()
funkce:
Player.prototype.setMove = function(mv) {
this.move = mv;
};
Při vyvolání této funkce pomocí player1.setMove('paper')
, this
odkazuje na hráče 1. Protože hráč1 nemá vlastní vlastnost move
, jeden je vytvořen! Každý hráč zavolá setMove()
, každý má nyní svůj vlastní move
vlastnost a move
na HumanPlayer.prototype
se již nikdy nepoužije.
player1.setMove('rock');
player2.setMove('paper');
console.log(player1.move, player2.move);
//rock paper
console.log(Object.getPrototypeOf(player1).move);
//null
Tentokrát jsme měli štěstí. Jak to správně opravit?
function Player(){
this.move = null;
}
function HumanPlayer() {
Player.call(this);
}
HumanPlayer.prototype = new Player();
let player1 = new HumanPlayer();
let player2 = new HumanPlayer();
console.log(player1.hasOwnProperty('move'));
//true
Zaměřte se na HumanPlayer
konstruktor - přidali jsme volání Player
konstruktér. Nyní vytvoření nového HumanPlayeru vyvolá konstruktor Player (s použitím kontextu objektu, který byl poprvé vytvořen kvůli new
) a nastaví move
vlastnost na tomto objektu. Nyní má každý hráč své vlastní vlastnosti. Se světem je vše v pořádku.