Что мы действительно имеем в виду, когда говорим о прототипах

1656539173 chto my dejstvitelno imeem v vidu kogda govorim o prototipah

автор Хейден Беттс

1*5dxjDGWBfN796dwrZcVHaw
Фото от rawpixel на Unsplash

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

1*L04gw3FTaj-fQE6b-bY2Ug
Но почему…?

Мне показалось, что я понял концепцию прототипов и прототипного наследования в JavaScript. Но меня продолжали смущать ссылки на «прототип» в коде и документации.

Много моего растерянности исчезло, когда я это понял Пишу о JavaScript, люди часто случайно используют «прототип». описать два разные, но родственные концепции.

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

Долгое время мне было удобно с определением 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.

1*XDj8pysP_Qt6QUc94J7tWw
1*fFxKUWpR7gkaIkoiHG4i3w

Но не было бы хорошо, если бы methodsForShowingAffection были инкапсулированы в createDog заводской функции? Это позволит понять, что эти методы предназначены для использования только с этой функцией. Итак, простой рефакторинг дает нам:

Рефактор 2: Прототипическое наследование + свойство прототипа на фабричные функции

Прекрасно! Но нет methodsForShowingAffection и длинное и удивительное название для собственности? Почему бы не использовать что-либо более общее и предполагаемое? Оказывается, дизайнеры Javascript предоставляют нам именно то, что мы ищем. Встроенный prototype свойство для каждой функции, в том числе для нашей заводской функцииcreateDog.

Заметьте, что в этом нет ничего особенного prototype собственность. Как показано выше, мы могли бы добиться точно такого же результата, установив прототип createDog на отдельный объект под названием methodsForShowingAffection. Нормальностьprototype свойство функций Javascript предлагает его предполагаемый вариант использования: удобство, предназначенное для облегчения общего шаблона проектирования. Ни больше, ни меньше.

Дальнейшее чтение:

Чтобы узнать больше о prototype свойство функций JavaScript, см. раздел «Прототип функции» в этом блоге Себастьяна Порту.

Статья MDN о прототипах.

Добавить комментарий

Ваш адрес email не будет опубликован.