Выразительный JavaScript (Хавербеке) - страница 60

, которое по умолчанию содержит простой пустой объект, происходящий от >Object.prototype. Каждый экземпляр, созданный этим конструктором, будет иметь этот объект в качестве прототипа. Поэтому, чтобы добавить кроликам, созданным конструктором >Rabbit, метод >speak, мы просто можем сделать так:

>Rabbit.prototype.speak = function(line) {

>  console.log("А " + this.type + " кролик говорит '" + line + "'");

>};

>blackRabbit.speak("Всем капец...");

>// → А чёрный кролик говорит 'Всем капец...'

Важно отметить разницу между тем, как прототип связан с конструктором (через свойство >prototype) и тем, как у объектов есть прототип (который можно получить через >Object.getPrototypeOf). На самом деле прототип конструктора – >Function.prototype, поскольку конструкторы – это функции. Его свойство >prototype будет прототипом экземпляров, созданных им, но не его прототипом.

Перегрузка унаследованных свойств

Когда вы добавляете свойство объекту, есть оно в прототипе или нет, оно добавляется непосредственно к самому объекту. Теперь это его свойство. Если в прототипе есть одноимённое свойство, оно больше не влияет на объект. Сам прототип не меняется.

>Rabbit.prototype.teeth = "мелкие";

>console.log(killerRabbit.teeth);

>// → мелкие

>killerRabbit.teeth = "длинные, острые и окровавленные";

>console.log(killerRabbit.teeth);

>// → длинные, острые и окровавленные

>console.log(blackRabbit.teeth);

>// → мелкие

>console.log(Rabbit.prototype.teeth);

>// → мелкие

На диаграмме нарисована ситуация после прогона кода. Прототипы >Rabbit и >Object находятся за >killerRabbit на манер фона, и у них можно запрашивать свойства, которых нет у самого объекта.



Перегрузка свойств, существующих в прототипе, часто приносит пользу. Пример с зубами кролика показывает, как её можно использовать для выражения каких-то исключительных характеристик конкретных экземпляров объектов, оставляя прочим стандартные значения из прототипа.

Та же перегрузка используется, чтобы дать стандартным функциям и массивам свои методы >toString, отличные от метода базового объекта.

>console.log(Array.prototype.toString == Object.prototype.toString);

>// → false

>console.log([1, 2].toString());

>// → 1,2

Вызов >toString массива выводит результат, похожий на >.join(",") – получается список, разделённый запятыми. Вызов >Object.prototype.toString напрямую для массива приводит к другому результату. Эта функция не знает ничего о массивах:

>console.log(Object.prototype.toString.call([1, 2]));

>// → [object Array]

Нежелательное взаимодействие прототипов

Прототип помогает в любое время добавлять новые свойства и методы всем объектам, которые основаны на нём. К примеру, нашим кроликам может понадобиться танец.