Введение

Стиль объектно-ориентированного программирования, в котором наследование основано на повторном использовании объектов. Прототипное программирование — это стиль объектно-ориентированного программирования, в котором повторное использование поведения (известное как наследование) осуществляется посредством процесса повторного использования существующих объектов, служащих прототипами. Эта модель также может называться прототипной, ориентированной на прототипы, бесклассовой или основанной на экземплярах. В прототипном программировании используются обобщенные объекты, которые затем можно клонировать и расширять. Например, объект "фрукт" представляет свойства и функциональность фруктов в целом. Объект "банан" клонируется из объекта "фрукт", и к нему добавляются общие свойства, специфичные для бананов. Каждый отдельный объект "банан" клонируется из обобщенного объекта "банан". Это отличается от парадигмы, основанной на классах, где класс "фрукт" расширяется классом "банан". Первыми языками прототипного программирования были Director, также известный как Ani (на базе MacLisp) (1976–1979), и одновременно, но независимо, ThingLab (на базе Smalltalk) (1977–1981) — докторские проекты Кеннета Майкла Кана в MIT и Алана Гамильтона Борнинга в Стэнфорде (при работе с Аланом Кеем в Xerox PARC). Борнинг ввел термин "прототип" в своей статье, опубликованной в TOPLAS в 1981 году. Первым языком прототипного программирования, имевшим более одного разработчика или пользователя, вероятно, был Yale T Scheme (1981–1984), который, как и Director и ThingLab изначально, оперировал только объектами без классов. Язык Self (1985–1995), разработанный Дэвидом Унгаром и Рэндаллом Смитом для исследования вопросов проектирования объектно-ориентированных языков, сделал термин и концепцию прототипов популярными. С конца 1990-х годов бесклассовая парадигма становится все более популярной. К современным прототипным языкам относятся JavaScript (и другие реализации ECMAScript, такие как JScript и ActionScript 1.0 для Flash), Lua, Cecil, NewtonScript, Io, Ioke, MOO, REBOL и AHK. С 2010-х годов появилось новое поколение языков с чистыми функциональными прототипами, сводящих ООП к его основе: Jsonnet — динамический, ленивый, чистый функциональный язык со встроенной объектной системой прототипов, использующей миксинное наследование; Nix — динамический, ленивый, чистый функциональный язык, создающий эквивалентную объектную систему (Nix "расширения") всего в двух коротких определениях функций (плюс множество других вспомогательных функций). Оба языка используются для определения крупных распределенных конфигураций программного обеспечения (Jsonnet непосредственно вдохновлен GCL, языком конфигурации Google, с помощью которого Google определяет все свои развертывания, и имеет схожую семантику, хотя и с динамической связью переменных). С тех пор другие языки, такие как Gerbil Scheme, реализовали чистые функциональные ленивые прототипные системы, основанные на аналогичных принципах.

Делегирование

В прототипных языках, использующих делегирование, среда выполнения языка способна вызывать нужный метод или находить необходимый фрагмент данных, просто следуя цепочке указателей делегирования (от объекта к его прототипу), пока не будет найдено соответствие. Для установления такого совместного использования поведения между объектами достаточно лишь указателя делегирования. В отличие от связи между классом и экземпляром в объектно-ориентированных языках, основанных на классах, связь между прототипом и его производными не требует, чтобы дочерний объект имел память или структурное сходство с прототипом, кроме этой самой связи. Таким образом, дочерний объект может продолжать изменяться и дополняться со временем, не требуя перестройки структуры связанного с ним прототипа, как это происходит в системах, основанных на классах. Важно также отметить, что добавлять или изменять можно не только данные, но и методы. По этой причине некоторые прототипные языки называют как данные, так и методы "слотами" или "членами".

Соединение

В цепном прототипировании, подходе, реализованном в языке программирования Kevo, отсутствуют видимые указатели или ссылки на исходный прототип, от которого клонируется объект. Прототип (родительский) объект копируется, а не связывается с ним, и делегирование не используется. Следовательно, изменения в прототипе не отразятся на клонированных объектах. К слову, язык программирования Cosmos достигает того же результата, используя постоянные структуры данных. Основное концептуальное отличие в данном случае заключается в том, что изменения, внесенные в прототипный объект, не распространяются автоматически на клоны. Это можно рассматривать как преимущество или недостаток. (Однако Kevo предоставляет дополнительные примитивы для распространения изменений между наборами объектов на основе их сходства – так называемые семейные сходства или механизм "клоновых семей". В отличие от этого, системы с прототипированием на основе делегирования могут использовать кэширование для ускорения поиска данных.

Критика

Сторонники объектных моделей, основанных на классах, критикующие системы, основанные на прототипах, часто испытывают опасения, схожие с теми, что высказывают сторонники систем статической типизации языков программирования в отношении систем динамической типизации (см. тип данных). Обычно эти опасения касаются корректности, безопасности, предсказуемости, эффективности и незнакомости программистов с данной парадигмой. По первым трем пунктам классы часто рассматриваются как аналоги типов (в большинстве статически типизированных объектно-ориентированных языков они выполняют именно эту функцию) и предлагаются для обеспечения контрактных гарантий своим экземплярам и пользователям этих экземпляров относительно их поведения. Что касается эффективности, объявление классов упрощает многие оптимизации компилятора, позволяющие разрабатывать эффективные механизмы поиска методов и переменных экземпляров. В случае языка Self значительное время было посвящено разработке, компиляции и интерпретации методов для повышения производительности систем, основанных на прототипах, по сравнению с системами, основанными на классах. Распространенная критика в адрес прототипных языков заключается в том, что сообщество разработчиков программного обеспечения недостаточно с ними знакомо, несмотря на популярность и широкое распространение JavaScript. Однако знания о прототипных системах растут по мере распространения JavaScript-фреймворков и усложнения использования JavaScript в развивающейся Всемирной паутине (Web). ECMAScript 6 представил классы как синтаксический сахар над существующей прототипной системой наследования в JavaScript, предоставляя альтернативный способ создания объектов и управления наследованием.