Прототипы - это оптимизация .
Отличным примером их правильного использования является библиотека jQuery.Каждый раз, когда вы получаете объект jQuery с помощью $('.someClass')
, этот объект имеет десятки «методов».Библиотека может достичь этого, возвращая объект:
return {
show: function() { ... },
hide: function() { ... },
css: function() { ... },
animate: function() { ... },
// etc...
};
Но это будет означать, что каждый объект jQuery в памяти будет иметь десятки именованных слотов, содержащих одни и те же методы, много раз.
Вместо этого эти методы определены в прототипе, и все объекты jQuery «наследуют» этот прототип, чтобы получить все эти методы с очень небольшими затратами времени выполнения.скрыто от программиста.Это рассматривается как оптимизация, а не то, о чем вам нужно беспокоиться при использовании библиотеки.
Проблема с JavaScript состоит в том, что функции голого конструктора требуют, чтобы вызывающая программа не забывала префиксировать их с new
, иначе оникак правило, не работают.Для этого нет веских причин.jQuery делает это правильно, скрывая эту ерунду за обычной функцией $
, поэтому вам не нужно заботиться о том, как реализованы объекты.
Чтобы вы могли удобно создать объект с указанным прототипом,ECMAScript 5 включает в себя стандартную функцию Object.create
.Очень упрощенная версия выглядела бы так:
Object.create = function(prototype) {
var Type = function () {};
Type.prototype = prototype;
return new Type();
};
Это просто избавляет от боли написания функции конструктора и последующего вызова с помощью new
.
Когда бы вы избежали прототипов?
Полезное сравнение с популярными ОО-языками, такими как Java и C #.Они поддерживают два вида наследования:
- интерфейс наследование, где вы
implement
и interface
так, что класс обеспечивает свою собственную уникальную реализацию для каждого члена интерфейса. - реализация наследование, где вы
extend
a class
, который обеспечивает реализации некоторых методов по умолчанию.
В JavaScript прототипическое наследование является своего рода реализация наследование.Таким образом, в тех ситуациях, когда (в C # или Java) вы должны были бы использовать базовый класс для получения поведения по умолчанию, которое затем вносилось бы небольшими изменениями с помощью переопределений, тогда в JavaScript прототипическое наследование имеет смысл.
ОднакоЕсли вы находитесь в ситуации, когда вы использовали бы интерфейсы в C # или Java, то вам не нужны какие-либо особые языковые функции в JavaScript.Нет необходимости явно объявлять что-то, представляющее интерфейс, и не нужно помечать объекты как «реализующие» этот интерфейс:
var duck = {
quack: function() { ... }
};
duck.quack(); // we're satisfied it's a duck!
Другими словами, если каждый «тип» объекта имеет свои собственные определения«методов», то нет смысла наследовать от прототипа.После этого это зависит от того, сколько экземпляров вы выделите для каждого типа.Но во многих модульных конструкциях есть только один экземпляр данного типа.
И на самом деле, многие люди предполагали, что наследование реализации - зло .То есть, если есть какие-то общие операции для типа, то, возможно, будет понятнее, если они не помещаются в базовый / супер класс, а вместо этого просто представляются как обычные функции в каком-то модуле, которому вы передаете объект (ы)Вы хотите, чтобы они оперировали.