Соглашение о наследовании прототипов в JavaScript
-
03-07-2019 - |
Вопрос
Я вижу много такого кода:
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;
или это не имеет особого значения?
Решение
«конструктор» не делает то, что выглядит.Это, помимо его нестандартности, является веской причиной избегать его использования — придерживайтесь экземпляров и прототипов.
Технически:«Конструктор» не является свойством экземпляра «s», это свойство просвечивающего объекта-прототипа «Sub».Когда вы создаете функцию Sub в Mozilla, вы получаете новый объект Sub.prototype по умолчанию, у которого есть «конструктор», указывающий обратно на функцию Sub в качестве любезности.
Однако затем вы заменяете этот прототип новым Base().Исходный прототип по умолчанию со ссылкой на Sub утерян;вместо этого Sub.prototype является экземпляром Base без какого-либо переопределяющего свойства «конструктор».Так:
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;
давайте использовать экземпляр, но есть лучшее решение.Смотри сюда:,Наследование TDD JS на GitHub , и найдите Паразитарное комбинированное наследование шаблон.Код создан на основе TDD, поэтому вы сможете очень быстро разобраться с ним, а затем просто изменить имена, чтобы начать работу.По сути, это то, что использует YAHOO.lang.extend (источник:сотрудник Yahoo и автор книги Николаса Закаса «Профессиональный JavaScript для веб-разработчиков», 2-е издание, стр. 181).Хорошая книга, кстати (ни в коем случае не связанная с ней!)
Почему?Поскольку классический шаблон, с которым вы работаете, имеет переменные ссылки на статику (если вы создадите var arr = [1,2] в базовом объекте, ВСЕ экземпляры будут иметь возможность чтения/записи и будут «совместно использовать состояние» «arr»!Если вы используете кражу конструктора, вы можете обойти это.Смотрите мои примеры.