Чому обидва хом’ячка наситились?
Ми маємо два хом’ячка (об’єкти): speedy
та lazy
, які успадковують властивості від загального об’єкта hamster
.
Коли ми годуємо одного з них, інший також стає ситим. Але чому? Як ми можемо це виправити?
let hamster = {
stomach: [],
eat(food) {
this.stomach.push(food);
}
};
let speedy = {
__proto__: hamster
};
let lazy = {
__proto__: hamster
};
// Цей хом’ячок знайшов їжу
speedy.eat("apple");
alert( speedy.stomach ); // apple
// Але цей також має їжу, чому? Виправте це.
alert( lazy.stomach ); // apple
Подивімося уважно, що відбувається у виклику speedy.eat("apple")
.
-
Метод
speedy.eat
знаходиться в прототипі (=hamster
), і виконується зthis=speedy
(об’єкт перед крапкою). -
Потім
this.stomach.push()
повинен знайти властивістьstomach
і викликатиpush
на ньому. Він шукаєstomach
вthis
(=speedy
), але нічого не знаходить. -
Далі
stomach
йде по ланцюжку прототипів доhamster
. -
Потім він викликає
push
на ньому, додаючи їжу до шлунку прототипу.
Таким чином, усі хом’ячки мають спільний шлунок!
Для обох методів lazy.stomach.push(...)
і speedy.stomach.push()
, властивість stomach
знаходисться в прототипі (бо в самих об’єктах такої властивості немає), яка отримує нові дані.
Зауважте, що така річ не відбувається у випадку простого визначення this.stomach=
:
let hamster = {
stomach: [],
eat(food) {
// визначається до `this.stomach` замість `this.stomach.push`
this.stomach = [food];
}
};
let speedy = {
__proto__: hamster
};
let lazy = {
__proto__: hamster
};
// Хом’ячок 'Speedy' знайшов їжу
speedy.eat("apple");
alert( speedy.stomach ); // apple
// Шлунок хом’ячка 'Lazy' пустий
alert( lazy.stomach ); // <нічого>
Тепер все працює добре, тому що this.stomach=
не виконує пошук властивості stomach
. Значення записується прямо в this
об’єкта.
Також, ми можемо узагалі уникнути проблеми визначивши шлунок для кожного хом’ячка окремо, ось так:
let hamster = {
stomach: [],
eat(food) {
this.stomach.push(food);
}
};
let speedy = {
__proto__: hamster,
stomach: []
};
let lazy = {
__proto__: hamster,
stomach: []
};
// Хом’ячок `Speedy` знайшов їжу
speedy.eat("яблуко");
alert( speedy.stomach ); // яблуко
// Шлунок хом’ячка `Lazy` пустий
alert( lazy.stomach ); // <нічого>
Отже, спільним рішенням може бути те, що всі властивості, які описують стан конкретного об’єкта (подібно як stomach
), повинні бути записані (визначені) в цьому ж самому об’єкті. Це уникне подібної проблеми.