Соглашение о наследовании прототипов в JavaScript - PullRequest
7 голосов
/ 31 декабря 2008

Я вижу много кода, подобного этому:

function Base() {}
function Sub() {}
Sub.prototype = new Base();

Однако, если вы сделаете:

s = new Sub();
print(s.constructor == Sub);

Это неверно. Мне кажется, что это сбивает с толку, так как конструктор s действительно является Sub Это обычно / лучше делать?

function Base() {}
function Sub() {}
Sub.prototype = new Base();
Sub.prototype.constructor = Sub;

или это не имеет значения?

Ответы [ 3 ]

9 голосов
/ 31 декабря 2008

'конструктор' не делает то, что выглядит, как он. Это, в дополнение к его нестандартности, является хорошим поводом избегать его использования - придерживайтесь instanceof и prototype.

Технически: 'constructor' не является свойством экземпляра 's', это свойство объекта-прототипа 'Sub', показывающего сквозь. Когда вы создаете функцию «Sub» в Mozilla, вы получаете недавно созданный по умолчанию объект Sub.prototype, у которого есть «конструктор», указывающий на функцию Sub в качестве любезности.

Однако затем вы заменяете этот прототип новым Base (). Исходный прототип по умолчанию со ссылкой на Sub потерян; вместо этого Sub.prototype является экземпляром Base без какого-либо переопределенного свойства 'constructor'. Итак:

new Sub().constructor===
Sub.prototype.constructor===
new Base().constructor===
Base.prototype.constructor===
Base

... вплоть до самого базового объекта, прототип которого вы не изменили.

Это обычно / лучше делать?

При работе с объектами / классами JavaScript не существует единого соглашения; Система метаклассов каждой библиотеки ведет себя немного по-разному. Я не видел ни одного, который записывал бы «конструктор» в каждый производный класс вручную, но это кажется таким же хорошим решением, как и любое, если вы действительно хотите, чтобы настоящий конструктор был доступен; это также сделает код совместимым с браузерами / движками, которые не дают вам конструктор.

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

3 голосов
/ 31 декабря 2008

Если вы хотите проверить, является ли объект именно экземпляром Sub, используйте оператор instanceof: -

print(s instanceof Sub);

Если вы хотите узнать, является ли объект экземпляром Sub или экземпляром подкласса Sub, используйте метод isPrototypeOf: -

print(Sub.prototype.isPrototypeOf(s));
1 голос
/ 29 октября 2009

Да,

Sub.prototype.constructor = Sub;

давайте воспользуемся instanceof, но есть лучшее решение. Посмотрите здесь: TDD JS Inheritance на GitHub и найдите шаблон Parasitic Combination Inheritance . Код TDD, так что вы должны иметь возможность очень быстро его обработать, а затем просто изменить имена, чтобы начать работу. Это в основном то, что использует YAHOO.lang.extend (источник: сотрудник Yahoo и автор Профессиональный JavaScript для веб-разработчика Николаса Закаса, 2-е издание, стр. 181). Кстати, хорошая книга (никак не связана!)

Почему? Поскольку у классического шаблона, с которым вы работаете, есть статические ссылочные переменные (если вы создадите var arr = [1,2] в базовом объекте, ВСЕ экземпляры будут иметь чтение / запись и будут иметь «общее состояние» «arr»! используйте конструктор кражи, вы можете обойти это. Смотрите мои примеры.

...