Введение
Стиль объектно-ориентированного программирования, в котором наследование основано на повторном использовании объектов. Прототипное программирование — это стиль объектно-ориентированного программирования, в котором повторное использование поведения (известное как наследование) осуществляется посредством процесса повторного использования существующих объектов, служащих прототипами. Эта модель также может называться прототипной, ориентированной на прототипы, бесклассовой или основанной на экземплярах. В прототипном программировании используются обобщенные объекты, которые затем можно клонировать и расширять. Например, объект "фрукт" представляет свойства и функциональность фруктов в целом. Объект "банан" клонируется из объекта "фрукт", и к нему добавляются общие свойства, специфичные для бананов. Каждый отдельный объект "банан" клонируется из обобщенного объекта "банан". Это отличается от парадигмы, основанной на классах, где класс "фрукт" расширяется классом "банан". Первыми языками прототипного программирования были 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, реализовали чистые функциональные ленивые прототипные системы, основанные на аналогичных принципах.
Prototype based programming is a style of object oriented programming in which behaviour reuse (known as inheritance) is performed via a process of reusing existing objects that serve as prototypes. This model can also be known as prototypal, prototype oriented, classless, or instance based programming. Prototype based programming uses the process generalized objects, which can then be cloned and extended. Using fruit as an example, a "fruit" object would represent the properties and functionality of fruit in general. A "banana" object would be cloned from the "fruit" object and general properties specific to bananas would be appended. Each individual "banana" object would be cloned from the generic "banana" object. Compare to the class based paradigm, where a "fruit" class would be extended by a "banana" class. The first prototype based programming languages were Director a. k. a. Ani (on top of MacLisp) (1976 1979), and contemporaneously and not independently, ThingLab (on top of Smalltalk) (1977 1981), respective PhD projects by Kenneth Michael Kahn at MIT and Alan Hamilton Borning at Stanford (but working with Alan Kay at Xerox PARC). Borning introduced the word "prototype" in his TOPLAS 1981 paper. The first prototype based programming language with more than one implementer or user was probably Yale T Scheme (1981 1984), though like Director and ThingLab initially, it just speaks of objects without classes. The language that made the name and notion of prototypes popular was Self (1985 1995), developed by David Ungar and Randall Smith to research topics in object oriented language design. Since the late 1990s, the classless paradigm has grown increasingly popular. Some current prototype oriented languages are JavaScript (and other ECMAScript implementations such as JScript and Flash's ActionScript 1.0), Lua, Cecil, NewtonScript, Io, Ioke, MOO, REBOL and AHK. Since the 2010s, a new generation of languages with pure functional prototypes has appeared, that reduce OOP to its very core: Jsonnet is a dynamic lazy pure functional language with a builtin prototype object system using mixin inheritance; Nix is a dynamic lazy pure functional language that builds an equivalent object system (Nix "extensions") in literally two short function definitions (plus many other convenience functions). Both languages are used to define large distributed software configurations (Jsonnet being directly inspired by GCL, the Google Configuration Language, with which Google defines all its deployments, and has similar semantics though with dynamic binding of variables). Since then, other languages like Gerbil Scheme have implemented pure functional lazy prototype systems based on similar principles.
Делегирование
В прототипных языках, использующих делегирование, среда выполнения языка способна вызывать нужный метод или находить необходимый фрагмент данных, просто следуя цепочке указателей делегирования (от объекта к его прототипу), пока не будет найдено соответствие. Для установления такого совместного использования поведения между объектами достаточно лишь указателя делегирования. В отличие от связи между классом и экземпляром в объектно-ориентированных языках, основанных на классах, связь между прототипом и его производными не требует, чтобы дочерний объект имел память или структурное сходство с прототипом, кроме этой самой связи. Таким образом, дочерний объект может продолжать изменяться и дополняться со временем, не требуя перестройки структуры связанного с ним прототипа, как это происходит в системах, основанных на классах. Важно также отметить, что добавлять или изменять можно не только данные, но и методы. По этой причине некоторые прототипные языки называют как данные, так и методы "слотами" или "членами".
Соединение
В цепном прототипировании, подходе, реализованном в языке программирования Kevo, отсутствуют видимые указатели или ссылки на исходный прототип, от которого клонируется объект. Прототип (родительский) объект копируется, а не связывается с ним, и делегирование не используется. Следовательно, изменения в прототипе не отразятся на клонированных объектах. К слову, язык программирования Cosmos достигает того же результата, используя постоянные структуры данных. Основное концептуальное отличие в данном случае заключается в том, что изменения, внесенные в прототипный объект, не распространяются автоматически на клоны. Это можно рассматривать как преимущество или недостаток. (Однако Kevo предоставляет дополнительные примитивы для распространения изменений между наборами объектов на основе их сходства – так называемые семейные сходства или механизм "клоновых семей". В отличие от этого, системы с прототипированием на основе делегирования могут использовать кэширование для ускорения поиска данных.
Критика
Сторонники объектных моделей, основанных на классах, критикующие системы, основанные на прототипах, часто испытывают опасения, схожие с теми, что высказывают сторонники систем статической типизации языков программирования в отношении систем динамической типизации (см. тип данных). Обычно эти опасения касаются корректности, безопасности, предсказуемости, эффективности и незнакомости программистов с данной парадигмой. По первым трем пунктам классы часто рассматриваются как аналоги типов (в большинстве статически типизированных объектно-ориентированных языков они выполняют именно эту функцию) и предлагаются для обеспечения контрактных гарантий своим экземплярам и пользователям этих экземпляров относительно их поведения. Что касается эффективности, объявление классов упрощает многие оптимизации компилятора, позволяющие разрабатывать эффективные механизмы поиска методов и переменных экземпляров. В случае языка Self значительное время было посвящено разработке, компиляции и интерпретации методов для повышения производительности систем, основанных на прототипах, по сравнению с системами, основанными на классах. Распространенная критика в адрес прототипных языков заключается в том, что сообщество разработчиков программного обеспечения недостаточно с ними знакомо, несмотря на популярность и широкое распространение JavaScript. Однако знания о прототипных системах растут по мере распространения JavaScript-фреймворков и усложнения использования JavaScript в развивающейся Всемирной паутине (Web). ECMAScript 6 представил классы как синтаксический сахар над существующей прототипной системой наследования в JavaScript, предоставляя альтернативный способ создания объектов и управления наследованием.