
Содержание статьи
автор Хейден Беттс

Начинающие разработчики JavaScript часто ошибочно используют одно слово – «прототип» – для обозначения двух разных концепций. Но какая разница между «прототипом объекта» и «свойством прототипа» функций JavaScript?

Мне показалось, что я понял концепцию прототипов и прототипного наследования в JavaScript. Но меня продолжали смущать ссылки на «прототип» в коде и документации.
Много моего растерянности исчезло, когда я это понял Пишу о JavaScript, люди часто случайно используют «прототип». описать два разные, но родственные концепции.
- Прототип объекта: объект шаблона, от которого другой объект JavaScript наследует методы и свойства. (MDN)
- Бесчисленное
prototype
свойство функций JavaScript: Удобство для облегчения дизайна шаблона (этот шаблон дизайна будет подробно объяснен вскоре!).
Сам по себе он не имеет смысла, пока намеренно не установлена определенная функция, связанная с наследованием. Самое полезное при использовании с функциями конструктора и фабричными функциями (объяснение будет!). Хотя все функции JS обладают свойством по умолчанию. Содержит аconstructor
свойство, относящееся к исходной функции.

Долгое время мне было удобно с определением 1, но не с определением 2.
Почему это различие имеет значение?
Ранее я понял разницу между «прототипом объекта» и «неперечисляемым» prototype
свойство функций», меня смутили следующие выражения:
Array.prototype.slice.call([1, 2], 0, 1);// [ 1 ]
(Боковая панель: первый, но не единственный шаг к пониманию вышесказанного – это понимание call()
. Вот быстрое обновление на всякий случай!)
Вопрос, на который я раньше не мог ответить:
- «Почему мы ищем
slice
вArray
прототип конструктора? Не следуетArray
сам конструктор содержит файлslice
метод, а его прототип просто содержит некоторые действительно низкоуровневые методы, общие для всех объектов?»
Эти вопросы были полностью прояснены, когда я понял шаблон дизайна prototype
имущество на Array
Для включения есть функции конструктора.
3 шага к пониманию свойства прототипа на функциях JS
Для того чтобы понятьprototype
свойство функций JS, вам нужно понять шаблон проектирования, который позволяет. Я буду понимать эту модель, сначала рассмотрев две менее предпочтительные альтернативы.
Реализация 1: Шаблон функционального класса
Представьте, что мы хотим создать игру, в которой мы общаемся с собаками. Мы хотим быстро создать много собак, которые имеют доступ к распространенным методам, например домашнее животное и дать угощать.
Мы могли бы начать реализовывать нашу игру, используя шаблон функционального класса следующим образом:
Давайте слегка почистим это, сохранив эти методы в собственном объекте. Затем вытащите их внутрь createDog
заводская функция.
Хотя эту реализацию легко понимать и удобно отражает наследование на основе классов в других языках, она имеет, по крайней мере, одну важную проблему: мы копируем определение наших методов к каждому объекту dog, который мы создаем с помощью нашей заводской функции.createDog
.
Это занимает больше памяти, чем необходимо, и не является СУХИМ. Не было бы хорошо, если бы вместо копирования определений методов до zeus
и casey
, мы могли бы определить наши методы в одном месте. Тогда мать zeus
и casey
указать на это место?
Рефактор 1: Реализация шаблона проектирования Прототипный класс.
Прототипное наследование дает нам то, о чем мы просили выше. Это позволит нам определить наши методы в одном объекте-прототипе. Тогда мать zeus
, casey
и нескончаемо больше подобных объектов указывают на этот прототип. zeus
и casey
затем будет иметь доступ ко всем методам и свойствам этого прототипа по ссылке.
ПРИМЕЧАНИЕ. Для менее знакомых существует много замечательных пособий, объясняющих концепцию прототипного наследования гораздо глубже, чем я здесь!
ПРИМЕЧАНИЕ ПО МОИМ ПРИМЕРАМ НИЖЕ: Для педагогической ясности я использую заводские функции с именем
createDog
, а не функции конструктора ES5 для реализации прототипной модели наследования. Я решил использовать фабричные функции, потому что у них меньше «магии, происходящей под капотом» и «синтаксического сахара», чем в конструкторах ES5. Надеемся, это облегчит сосредоточение внимания на проблеме!
Прекрасно! Теперь отвечающие объекты zeus
и casey
сами по себе не содержат копий методов giveTreat
и pet
. Объекты ищут эти методы в своем прототипе.methodsForShowingAffection
.


Но не было бы хорошо, если бы methodsForShowingAffection
были инкапсулированы в createDog
заводской функции? Это позволит понять, что эти методы предназначены для использования только с этой функцией. Итак, простой рефакторинг дает нам:
Рефактор 2: Прототипическое наследование + свойство прототипа на фабричные функции
Прекрасно! Но нет methodsForShowingAffection
и длинное и удивительное название для собственности? Почему бы не использовать что-либо более общее и предполагаемое? Оказывается, дизайнеры Javascript предоставляют нам именно то, что мы ищем. Встроенный prototype
свойство для каждой функции, в том числе для нашей заводской функцииcreateDog
.
Заметьте, что в этом нет ничего особенного prototype
собственность. Как показано выше, мы могли бы добиться точно такого же результата, установив прототип createDog
на отдельный объект под названием methodsForShowingAffection
. Нормальностьprototype
свойство функций Javascript предлагает его предполагаемый вариант использования: удобство, предназначенное для облегчения общего шаблона проектирования. Ни больше, ни меньше.
Дальнейшее чтение:
Чтобы узнать больше о prototype
свойство функций JavaScript, см. раздел «Прототип функции» в этом блоге Себастьяна Порту.
Статья MDN о прототипах.