Мастер-классы по Javascript Екатеринбург Ростов-на-Дону Москва Узнать больше...
Содержание (скрыть) Содержание (показать)

Хомяки с __proto__

Вы — руководитель команды, которая разрабатывает игру, хомяковую ферму. Один из программистов получил задание создать псевадокласс хомяк "Hamster".

Объекты-хомяки должны иметь массив food для хранения еды и метод found, который добавляет к нему.

Ниже — его решение. При создании двух хомяков, если поел один — почему-то сытым становится и второй тоже.

В чём дело? Как поправить?

function Hamster() {  }

copy(Hamster.prototype, {
  food: [],
  found: function(something) {
    this.food.push(something)
  }
});

// Создаём двух хомяков и кормим первого
speedy = new Hamster();
lazy = new Hamster();

speedy.found("яблоко");
speedy.found("орех");

alert(speedy.food.length); // 2
alert(lazy.food.length);   // 2 (!??)


/* вспомогательная функция copy(dst, src1, src2...) */
function copy(dst) {
  for(var i=1; i<arguments.length; i++) {
    var obj = arguments[i];
    for(var key in obj) dst[key] = obj[key];
  }
  return dst;
}

Решение, шаг 1
Решение
Решение, шаг 1

Давайте подробнее разберем происходящее при вызове speedy.found("яблоко"):

  1. Интерпретатор ищет свойство found в speedy. Но speedy — пустой объект, т.к. new Hamster ничего не делает с this.
  2. Интерпретатор идёт по ссылке speedy.__proto__ (==Hamster.prototype) и находят там метод found, запускает его.
  3. Значение this устанавливается в объект перед точкой, т.е. в speedy.
  4. Для выполнения this.food.push() нужно найти свойство this.food. Оно отсутствует в speedy, но есть в speedy.__proto__.
  5. Значение "яблоко" добавляется в speedy.__proto__.food.

У всех хомяков общий живот! Или, в терминах JavaScript, свойство food изменяется в прототипе, который является общим для всех объектов-хомяков.

Заметим, что этой проблемы не было бы при простом присваивании:

this.food = something;

В этом случае значение записалось бы в сам объект, без поиска found в прототипе.

Проблема возникает только со свойствами-объектами в прототипе.

Исправьте её?

Решение, шаг 2
Решение, шаг 2

Для исправления проблемы нужно дать каждому хомяку свой живот. Это можно сделать, присвоив его в конструкторе.

function Hamster() { 
*!*
  this.food = [];
*/!*
}

copy(Hamster.prototype, {
  // food: [], копируем только метод
  found: function(something) {
    this.food.push(something)
  }
});

speedy = new Hamster();
lazy = new Hamster();

speedy.found("яблоко");
speedy.found("орех");

alert(speedy.food.length) // 2
alert(lazy.food.length) // 0(!)



/* вспомогательная функция copy(dst, src1, src2...) */
function copy(dst) {
  for(var i=1; i<arguments.length; i++) {
    var obj = arguments[i];
    for(var key in obj) dst[key] = obj[key];
  }
  return dst;
}

#168
Наверх

Реклама

Нашли опечатку?

Нашли опечатку на сайте? Что-то кажется странным?
Выделите соответствующий текст и нажмите Ctrl+Enter!

Последние Комментарии

Помоги другим!

Помоги другим узнать о хорошей статье!