Wartości lokalne vs. dziedziczone
Gdy korzystasz z dostępu do własności obiektu, JavaScript wykonuje następujące kroki, tak jak opisano w poprzednim rozdziale:
- Sprawdza czy wartość istnieje lokalnie. Jeśli tak, to zwraca tę wartość.
- Jeśli wartość lokalna nie istnieje, sprawdza łańcuch prototypu (używając własności
__proto__
). - Jeśli obiekt w łańcuchu prototypu posiada wartość dla określonej wartości, zwraca tę wartość.
- Jeśli własność ta nie została odnaleziona, to obiekt nie posiada tej własności.
Rezultat tych kroków zależy od sposobu, w jaki definiujesz rzeczy w kodzie. Oyginalny przykład używał następujących definicji:
function Employee () { this.name = ""; this.dept = "general"; } function WorkerBee () { this.projects = []; } WorkerBee.prototype = new Employee;
Przypuśćmy, że wraz z tymi definicjami utworzyłeś amy
jako instancję WorkerBee
za pomocą poniższej instrukcji:
amy = new WorkerBee;
Obiekt amy
posiada jedną lokalną własność, projects
. Wartości własności name
i dept
nie są lokalne dla amy
i dlatego są pobrane z własności __proto__
obiektu amy
. W ten sposób amy
posiada następujące wartości własności:
amy.name == ""; amy.dept = "general"; amy.projects == [];
Teraz przypuśćmy, że zmienisz wartość własności name
w prototypie powiązanym z Employee
:
Employee.prototype.name = "Unknown"
Na pierwszy rzut oka może Ci sie wydawać, że nowa wartość zostanie przekazana dalej do wszystkich instancji Employee
. Nie dzieje się tak.
Gdy tworzysz dowolną instancję obiektu Employee
, instancja ta otrzymuje lokalną wartość dla własności name
(pusty ciąg znaków). Oznacza to, że gdy ustawisz prototyp WorkerBee
poprzez utworzenie nowego obiektu Employee
, WorkerBee.prototype
posiada lokalną wartość dla własności name
. Dlatego więc, gdy JavaScript sprawdza własność name
obiektu amy
(instancji WorkerBee
), JavaScript znajduje lokalną wartość dla tej własności w WorkerBee.prototype
. Dlatego też nie sprawdza on łańcucha dalej aż do Employee.prototype
.
Jeśli chcesz zmienić wartość własności obiektu w momencie uruchomienia i sprawić, by była ona dziedziczona przez wszystkich potomków obiektu, nie możesz zdefiniować własności w funkcji konstruktora obiektu. Zamiast tego dodaj ją do prototypu powiązanego z konstruktorem. Na przykład, zakładając zmianę poprzedniego kodu na poniższy:
function Employee () { this.dept = "general"; } Employee.prototype.name = ""; function WorkerBee () { this.projects = []; } WorkerBee.prototype = new Employee; amy = new WorkerBee; Employee.prototype.name = "Unknown";
W tym wypadku własność name
obiektu amy
przyjmuje wartość "Unknown".
Jak pokazuję powyższe przykłady, jeśli chcesz zachować domyślne wartości dla własności obiektu i móc zmienić domyślne wartości w momencie uruchomienia, powinieneś utworzyć własności w prototypie konstruktora, a nie w samej funkcji konstruktora.