Зачем использовать прикованное наследование прототипа в javascript?

perf

Почему мы создаем цепочку наследования прототипа, а не используя композицию объекта. Поиск прототипа для каждого шага в цепочке становится дорогим.

Вот пример кода-примера:

var lower  = {
    "foo": "bar"
};

var upper = {
    "bar": "foo"
};

var chained = Object.create(lower,  pd(upper));

var chainedPrototype = Object.create(chained);

var combinedPrototype = Object.create(pd.merge(lower, upper));

var o1 = Object.create(chainedPrototypes);
var o2 = Object.create(combinedPrototypes);

использует pd, поскольку дескрипторы свойств являются подробными как ад.

o2.foo быстрее, чем o1.foo, поскольку он поднимается только на две прототипные цепи, а не на три.

Так как путешествие вверх по прототипной цепи дорого, почему мы строим один вместо использования композиции объекта?

Еще один лучший пример:

var Element = {
  // Element methods
}

var Node = {
  // Node methods
}

var setUpChain = Object.create(Element, pd(Node));
var chained = Object.create(setUpChain);
var combined = Object.create(pd.merge(Node, Element));

document.createChainedElement = function() {
  return Object.create(chained);
}

document.createCombinedElement = function() {
  return Object.create(combined);
}

Я не вижу каких-либо кодов, объединяющих объекты прототипа для повышения эффективности. Я вижу много кода, создающих прототипы. Почему последние популярны?

Единственная причина, по которой я могу думать, - это использовать Object.isPrototypeOf для проверки отдельных прототипов в вашей цепочке.

Помимо isPrototypeOf существуют ли явные преимущества использования наследования над композицией?

Ответ 1

Основная причина должна заключаться в изменении объекта-прототипа. Изменение объекта предка будет отражено по всей цепочке. Возможно, это может быть выгодным. Хотя я не могу сразу думать о каких-либо реальных экземплярах, я думаю, что охват этого динамического характера может обеспечить динамику, которую другие (читаемые: на основе класса) языки просто не предоставляют.

Объекты, продвигающие цепочку прототипов, могут развиваться по мере необходимости на протяжении всего срока службы приложения, и эти изменения будут отражаться на всех объектах-потомках. Это может быть легко объединено с функциями JavaScript как первоклассные объекты для динамического изменения функциональности по мере необходимости.

Тем не менее, если эта функциональность не нужна, нет причин использовать цепочку прототипов над композицией.

Ответ 2

Хорошо, подумайте, что произойдет, если изменится lower или upper. Комбинированный прототип не отражает это изменение, поскольку вы создали новый объект, скопировав из них свойства.

Для многих ситуаций это будет хорошо, но это не так динамично, как фактически создавать правильные цепи прототипов для ваших объектов.

Ответ 3

Вот некоторые преимущества, которые я могу придумать в порядке важности

Использование памяти

Используя прототип, вы создаете общие свойства. Ваш подход копирует все значения в каждый объект.

Первоначальная стоимость настройки объектов

Мысль о том, что вы сэкономите немного времени спустя, вы вынуждены оплачивать стоимость копирования при настройке объекта. Было бы хорошо, если бы вы учли это в своих тестах производительности. Это преимущество, которое может быть перевешено, если вы читаете намного больше, чем задаете свои объекты.

InstanceOf

Хороший код не использует instanceOf, но иногда вы не можете сделать весь свой код идеальным, поэтому зачем ломать язык?

Динамическое изменение прототипа

Большинство людей утверждают, что они никогда не нуждаются в этом (как и я), но многие из нас расширили Array.prototype после создания экземпляров некоторых массивов (не то, что вы должны это сделать). При подходе к свойствам копирования вы теряете ссылку на исходный объект.

Unashamed plug: http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html

Последняя заметка Если вы на самом деле являетесь узким местом в приложении, я бы не захотел использовать его для рассматриваемых объектов