Существует множество примеров наследования прототипов в дикой природе. Примечательно, что JQuery использует его. Каждый раз, когда вы делаете выбор jQuery, вы используете прототип делегата для наследования методов jQuery. Он также широко используется в различных веб-приложениях, включая платформу Creative Cloud от Abode, многие продукты от Yahoo и т. Д. *
Фактически, каждая реализация классического наследования в JavaScript фактически использует наследование прототипа для имитации классического наследования - необходимо только для удобства программистов, которые больше знакомы с классическим, чем с наследованием прототипов. Наследование прототипа настолько гибко, что легко имитировать особенности классического наследования с использованием наследования прототипа. Обратное неверно.
Прототипное наследование означает просто, что объект наследуется непосредственно от другого объекта. Вот пример:
var switchProto = {
isOn: function isOn() {
return this.state;
},
toggle: function toggle() {
this.state = !this.state;
return this;
},
state: false
},
switch1 = Object.create(switchProto),
switch2 = Object.create(switchProto);
Обычно этот вызов Object.create()
помещают в фабричную функцию, чтобы сделать создание объекта более удобным.
Существует множество проблем с классическим наследованием, которых не существует с наследованием прототипов, таких как:
Классическое наследство
Плотная муфта . Наследование - самая прочная связь, доступная в дизайне OO. У классов потомков есть глубокие знания классов их предков.
Негибкие иерархии (дублирование по необходимости) . Иерархии с одним родителем редко способны описать все возможные варианты использования. В конце концов, все иерархии «неправильны» для нового использования - проблема, которая требует дублирования кода.
Многократное наследование сложно . Часто желательно наследовать от более чем одного родителя. Этот процесс чрезмерно сложен, и его реализация несовместима с процессом одиночного наследования, что затрудняет его чтение и понимание.
Хрупкая архитектура . Из-за тесной связи часто бывает трудно реорганизовать класс с «неправильным» дизайном, потому что большая часть существующих функций зависит от существующего дизайна.
Проблема Гориллы / Банана . Часто есть части родительского объекта, которые вы не хотите наследовать. Подклассы позволяют переопределять свойства родительского объекта, но не позволяют выбирать, какие свойства вы хотите наследовать.
Прототип наследования
Чтобы понять, как наследование прототипа решает эти проблемы, вы должны сначала понять, что существует два разных типа наследования прототипа. JavaScript поддерживает оба:
Делегирование . Если свойство не найдено в экземпляре, оно ищется в прототипе экземпляра. Это позволяет вам совместно использовать методы среди многих экземпляров, предоставляя вам шаблон flyweight бесплатно .
конкатенация . Возможность динамического добавления свойств к объекту позволяет свободно копировать любые свойства из одного объекта в другой, все вместе или выборочно.
Вы можете комбинировать обе формы наследования прототипов для достижения очень гибкой системы повторного использования кода. Настолько гибкая, что реализовать классическое наследование с помощью прототипов тривиально. Обратное неверно.
Прототипное наследование позволяет большинство важных функций, которые вы найдете в классических языках. В JavaScript замыкания и фабричные функции позволяют реализовать частное состояние, а функциональное наследование можно легко комбинировать с прототипами, чтобы также добавлять миксины, поддерживающие конфиденциальность данных.
Некоторые преимущества наследования прототипа:
Слабая связь . Экземпляр никогда не нуждается в прямой ссылке на родительский класс или прототип. Можно сохранить ссылку на прототип объекта, но это не рекомендуется, потому что это будет способствовать тесной связи в иерархии объектов - одна из самых больших ошибок классического наследования.
Плоские иерархии . С прототипом ОО тривиально сохранять иерархии наследования плоскими - используя конкатенацию и делегирование, вы можете иметь один уровень делегирования объекта и один экземпляр без ссылок на родительские классы.
Тривиальное множественное наследование . Наследование от нескольких предков так же просто, как объединение свойств из нескольких прототипов с использованием конкатенации для формирования нового объекта или нового делегата для нового объекта.
Гибкая архитектура . Поскольку вы можете выборочно наследовать с помощью прототипа OO, вам не нужно беспокоиться о проблеме «неправильного дизайна». Новый класс может наследовать любую комбинацию свойств от любой комбинации исходных объектов. Из-за простоты выравнивания иерархии изменение в одном месте не обязательно вызывает рябь в длинной цепочке объектов-потомков.
Горилл больше нет . Выборочное наследование устраняет проблему бананов горилл.
Мне не известно о каких-либо преимуществах, которые классическое наследование имеет по сравнению с прототипным наследованием. Если кто-нибудь знает о них, пожалуйста, просветите меня.