Так что все эти годы я, наконец, перестал тянуть ноги и решил «правильно» выучить JavaScript. Одним из самых головокружительных элементов дизайна языков является реализация наследования. Имея опыт работы с Ruby, я был очень рад видеть замыкания и динамическую типизацию; но за всю жизнь я не могу понять, какие выгоды можно получить от экземпляров объектов, использующих другие экземпляры для наследования.
271
Ответы:
Я знаю, что этот ответ опоздал на 3 года, но я действительно думаю, что текущие ответы не дают достаточно информации о том, насколько наследование прототипа лучше, чем классическое наследование .
Сначала давайте рассмотрим наиболее распространенные аргументы, которые программисты JavaScript заявляют в защиту наследования прототипа (я беру эти аргументы из текущего пула ответов):
Теперь все эти аргументы верны, но никто не удосужился объяснить, почему. Это все равно, что сказать ребенку, что изучение математики важно. Конечно, но ребенку все равно; и вы не можете сделать ребенка, как математика, сказав, что это важно.
Я думаю, что проблема наследования прототипов заключается в том, что это объясняется с точки зрения JavaScript. Я люблю JavaScript, но наследование прототипов в JavaScript неверно. В отличие от классического наследования, существует два типа наследования прототипа:
К сожалению, JavaScript использует шаблон конструктора прототипного наследования. Это потому, что когда был создан JavaScript, Брендан Эйх (создатель JS) хотел, чтобы он выглядел как Java (который имеет классическое наследование):
Это плохо, потому что когда люди используют конструкторы в JavaScript, они думают о конструкторах, наследуемых от других конструкторов. Это не верно. В прототипе объекты наследования наследуются от других объектов. Конструкторы никогда не входят в картину. Это то, что смущает большинство людей.
Люди из таких языков, как Java, которые имеют классическое наследование, становятся еще более запутанными, потому что, хотя конструкторы выглядят как классы, они не ведут себя как классы. Как сказал Дуглас Крокфорд :
Там у вас есть это. Прямо изо рта лошади.
Истинное наследование прототипа
Наследование прототипа - все об объектах. Объекты наследуют свойства от других объектов. Это все, что нужно сделать. Существует два способа создания объектов с использованием наследования прототипов:
Примечание. JavaScript предлагает два способа клонирования объекта: делегирование и конкатенация . Впредь я буду использовать слово «клон», чтобы ссылаться исключительно на наследование через делегирование, а слово «копировать» - исключительно на наследование через конкатенацию.
Хватит разговоров. Давайте посмотрим несколько примеров. Скажи, у меня есть круг радиуса
5
:Мы можем рассчитать площадь и окружность круга по его радиусу:
Теперь я хочу создать еще один круг радиуса
10
. Один из способов сделать это будет:Однако JavaScript обеспечивает лучший способ - делегирование .
Object.create
Функция используется , чтобы сделать это:Вот и все. Вы только что сделали прототип наследования в JavaScript. Разве не так просто? Вы берете объект, клонируете его, меняете все, что вам нужно, и, эй, давай - у тебя есть новый объект.
Теперь вы можете спросить: «Как это просто? Каждый раз, когда я хочу создать новый круг, мне нужно клонировать
circle
и вручную назначить ему радиус». Ну, решение состоит в том, чтобы использовать функцию для выполнения тяжелой работы за вас:Фактически вы можете объединить все это в один литерал объекта следующим образом:
Прототип наследования в JavaScript
Если вы заметили в приведенной выше программе,
create
функция создает клонcircle
, назначает новыйradius
и затем возвращает его. Это именно то, что конструктор делает в JavaScript:Шаблон конструктора в JavaScript - это инвертированный прототип. Вместо создания объекта вы создаете конструктор.
new
Ключевое слово связываетthis
указатель внутри конструктора клонprototype
конструктора.Звучит запутанно? Это потому, что шаблон конструктора в JavaScript излишне усложняет вещи. Это то, что большинству программистов трудно понять.
Вместо того чтобы думать об объектах, унаследованных от других объектов, они думают о конструкторах, наследующих от других конструкторов, и затем полностью запутываются.
Существует целый ряд других причин, по которым следует избегать использования шаблона конструктора в JavaScript. Вы можете прочитать о них в моем блоге здесь: Конструкторы против прототипов
Так в чем же преимущества наследования прототипа перед классическим наследованием? Давайте снова рассмотрим наиболее распространенные аргументы и объясним, почему .
1. Прототип наследования прост
CMS заявляет в своем ответе:
Давайте рассмотрим, что мы только что сделали. Мы создали объект,
circle
который имел радиус5
. Затем мы его клонировали и дали клону радиус10
.Следовательно, нам нужны только две вещи, чтобы заставить наследование прототипа работать:
Object.create
).В отличие от классического наследования гораздо сложнее. В классическом наследовании у вас есть:
Вы поняли идею. Дело в том, что наследование прототипов легче понять, легче реализовать и легче рассуждать.
Как пишет Стив Йегге в своем классическом посте в блоге « Портрет N00b »:
В этом же смысле классы - это просто метаданные. Классы не обязательны для наследования. Однако некоторые люди (обычно n00bs) находят классы более удобными для работы. Это дает им ложное чувство безопасности.
Как я уже говорил ранее, занятия дают людям ложное чувство безопасности. Например, вы получаете слишком много
NullPointerException
s в Java, даже когда ваш код отлично читается. Я считаю, что классическое наследование обычно мешает программированию, но, возможно, это просто Java. У Python удивительная классическая система наследования.2. Прототип наследования является мощным
Большинство программистов, которые имеют классический опыт, утверждают, что классическое наследование является более мощным, чем наследование прототипов, потому что оно имеет:
Это утверждение является ложным. Мы уже знаем, что JavaScript поддерживает закрытые переменные через замыкания , но как насчет множественного наследования? Объекты в JavaScript имеют только один прототип.
Правда в том, что наследование прототипов поддерживает наследование от нескольких прототипов. Прототип наследования просто означает, что один объект наследуется от другого объекта. Существует два способа реализации наследования прототипов :
Да, JavaScript позволяет объектам делегироваться только одному объекту. Однако это позволяет копировать свойства произвольного числа объектов. Например,
_.extend
делает именно это.Конечно , многие программисты не считают , что это верно , так как наследование
instanceof
иisPrototypeOf
сказать иначе. Однако это можно легко исправить, сохранив массив прототипов для каждого объекта, который наследуется от прототипа путем конкатенации:Следовательно, наследование прототипов так же сильно, как и классическое наследование. На самом деле это намного более мощно, чем классическое наследование, потому что в наследовании прототипов вы можете вручную выбрать, какие свойства копировать, а какие свойства опускать в разных прототипах.
В классическом наследовании невозможно (или, по крайней мере, очень сложно) выбрать, какие свойства вы хотите наследовать. Они используют виртуальные базовые классы и интерфейсы для решения алмазной проблемы .
Однако в JavaScript вы, скорее всего, никогда не услышите о проблеме с бриллиантами, поскольку вы можете точно контролировать, какие свойства вы хотите унаследовать и от каких прототипов.
3. Прототип наследования менее избыточен
Этот момент немного сложнее объяснить, потому что классическое наследование не обязательно приводит к более избыточному коду. Фактически наследование, классическое или прототипное, используется для уменьшения избыточности в коде.
Одним из аргументов может быть то, что большинство языков программирования с классическим наследованием статически типизированы и требуют от пользователя явного объявления типов (в отличие от Haskell, который имеет неявную статическую типизацию). Следовательно, это приводит к более подробному коду.
Ява печально известна этим поведением. Я отчетливо помню, как Боб Нистром упомянул следующий анекдот в своем блоге о парсерах Pratt :
Опять же, я думаю, что это только потому, что Java так много отстой.
Одним из веских аргументов является то, что не все языки с классическим наследованием поддерживают множественное наследование. Снова на ум приходит Java. Да, в Java есть интерфейсы, но этого недостаточно. Иногда вам действительно нужно множественное наследование.
Поскольку наследование прототипа допускает множественное наследование, код, который требует множественного наследования, менее избыточен, если написан с использованием наследования прототипа, а не на языке, который имеет классическое наследование, но не множественное наследование.
4. Прототип наследования является динамическим
Одним из наиболее важных преимуществ наследования прототипов является то, что вы можете добавлять новые свойства в прототипы после их создания. Это позволяет вам добавлять новые методы в прототип, которые будут автоматически доступны для всех объектов, которые делегируют этот прототип.
Это невозможно в классическом наследовании, потому что после создания класса вы не сможете изменить его во время выполнения. Это, вероятно, самое большое преимущество наследования прототипа перед классическим наследованием, и оно должно было быть на вершине. Однако мне нравится сохранять лучшее для конца.
Вывод
Прототип наследования имеет значение. Важно обучить программистов на JavaScript тому, почему следует отказаться от шаблона конструктора наследования прототипа в пользу модели прототипа наследования прототипа.
Нам нужно начать учить JavaScript правильно, а это значит показать новым программистам, как писать код, используя шаблон-прототип вместо шаблона-конструктора.
Мало того, что будет проще объяснить наследование прототипа, используя шаблон прототипа, но это также сделает лучших программистов.
Если вам понравился этот ответ, то вам также следует прочитать мой пост в блоге " Почему вопросы наследования прототипов ". Поверьте мне, вы не будете разочарованы.
источник
Object.create
создает новый объект с указанным прототипом. Ваш выбор слов создает впечатление, что прототип клонируется.Позвольте мне на самом деле ответить на вопрос в строке.
Наследование прототипа имеет следующие достоинства:
Однако имеет следующие недостатки:
Я думаю, что вы можете читать между строк выше и придумать соответствующие преимущества и недостатки традиционных схем классов / объектов. Разумеется, в каждой области их больше, поэтому остальное оставлю на усмотрение других людей.
источник
ИМО основным преимуществом наследования прототипа является его простота.
Прототипная природа языка может сбить с толку людей с классической подготовкой, но оказывается, что на самом деле это действительно простая и мощная концепция дифференциального наследования .
Вам не нужно делать классификацию , ваш код меньше, менее избыточен, объекты наследуются от других, более общих объектов.
Если вы будете мыслить прототипами, вы скоро заметите, что вам не нужны занятия ...
В ближайшем будущем наследование прототипов станет гораздо более популярным, в спецификации ECMAScript 5-го издания был представлен
Object.create
метод, который позволяет вам создавать новый экземпляр объекта, который наследуется от другого, очень простым способом:Эта новая версия стандарта внедряется всеми поставщиками браузеров, и я думаю, что мы начнем видеть более чистое наследование прототипов ...
источник
Там действительно не так много, чтобы выбрать между этими двумя методами. Основная идея заключается в том, что когда движку JavaScript присваивается свойство объекта для чтения, он сначала проверяет экземпляр, а если это свойство отсутствует, он проверяет цепочку прототипов. Вот пример, который показывает разницу между прототипом и классическим:
прототипичный
Классический с методами экземпляра (Неэффективно, потому что каждый экземпляр хранит свое собственное свойство)
Эффективный классический
Как вы можете видеть, поскольку можно манипулировать прототипом «классов», объявленных в классическом стиле, использование наследования прототипа не дает никаких преимуществ. Это подмножество классического метода.
источник
Веб-разработка: прототип наследования против классического наследования
http://chamnapchhorn.blogspot.com/2009/05/prototypal-inheritance-vs-classical.html
Классическое наследование против прототипа - переполнение стека
Классический Vs прототип наследования
источник