Соглашение о наследовании прототипа в JavaScript
Я вижу много кода, как это:
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 ответа
"конструктор" не делает то, что выглядит Это, в дополнение к его нестандартности, является хорошей причиной, чтобы избегать его использования - придерживайтесь 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 не существует единого соглашения; Система метаклассов каждой библиотеки ведет себя немного по-разному. Я не видел ни одного, который записывал бы "конструктор" в каждый производный класс вручную, но это кажется таким же хорошим решением, как и любое, если вы действительно хотите, чтобы настоящий конструктор был доступен; это также сделает код совместимым с браузерами / движками, которые не дают вам конструктор.
Однако я хотел бы дать ему другое имя, чтобы избежать путаницы с существующим и отличающимся поведением "конструктором".
Если вы хотите проверить, является ли объект именно экземпляром Sub, используйте instanceof
Оператор:-
print(s instanceof Sub);
Если вы хотите узнать, является ли объект экземпляром Sub или экземпляром подкласса Sub, используйте isPrototypeOf
Метод:-
print(Sub.prototype.isPrototypeOf(s));
Да уж,
Sub.prototype.constructor = Sub;
давайте использовать instanceof, но есть лучшее решение. Посмотрите здесь:, TDD JS Inheritance на GitHub, и найдите паттерн наследования паразитных комбинаций. Код TDD, так что вы должны иметь возможность очень быстро его найти, а затем просто изменить имена, чтобы начать работу. Это в основном то, что использует YAHOO.lang.extend (источник: сотрудник Yahoo и автор Профессиональный JavaScript для веб-разработчика Николаса Закаса, 2-е издание, стр. 181). Кстати, хорошая книга (никак не связана!)
Зачем? Поскольку у классического шаблона, с которым вы работаете, есть статические ссылочные переменные (если вы создадите var arr = [1,2] в базовом объекте, ВСЕ экземпляры будут иметь чтение / запись и будут иметь "общее состояние" 'arr'! Если вы использовать конструктор краже вы можете обойти это. Смотрите мои примеры.