Comments 19
Кстати, сейчас новые браузеры поддерживают Object.create, поэтому я последнее время стал использовать такой шаблон:
Object.extend (нестандартный метод) просто копирует свойства. Object.create для старых браузеров сделать просто.
function MyClass(…) {
…
}
MyClass.prototype = Object.extend(Object.create(MyOtherClass.prototype), {
constructor: MyClass,
…
});
Object.extend (нестандартный метод) просто копирует свойства. Object.create для старых браузеров сделать просто.
Онеееет, ещё одно наследование в JS…
Ну сколько можно? Почему каждый начинающий программист на JS пишет сначала своё наследование, потом свои события, потом свою систему модулей?
Ну сколько можно? Почему каждый начинающий программист на JS пишет сначала своё наследование, потом свои события, потом свою систему модулей?
Вероятно потому, что именно на процессе создания велосипедов и зиждется понимание концепций?
Но зачем же это выкладывать? Да и для более глубокого понимания JS ни в уоем случае нельзя первым делом туда тащить за уши объектную модель из других языков.
Она в JS и своя неплохая: для развития стоит, наверное, попробовать думать по-другому, а не тащить с собой багаж костылей с других языков.
Она в JS и своя неплохая: для развития стоит, наверное, попробовать думать по-другому, а не тащить с собой багаж костылей с других языков.
Мне кажется, неплохая она в первую очередь по тому, что позволяет её изменять, писать мощные фреймворки. Вот я всегда пытался писать через стандартную, и для небольших скриптов она великолепна, но при создании проектов побольше рутина и излишки байтов привели к такому варианту.
Приведу, что-ли, свой пример наследования. Может кому понадобится:
Object.inherit = function(Child, Parent) {
(Child.prototype = Object.create(Child.superclass = Parent.prototype)).constructor = Child;
}
/** @constructor */
function A() {
this.say = function() { console.log("may") }
this.init = function() { console.log("init A instance") }
}
/** @constructor */
function B() {
B.superclass.constructor.apply(this, arguments);//A.apply(this, arguments);
/** @override */
this.say = function() { console.log("gav") }
var superInit = this.init;
this.init = function() {
superInit();//Parent `init` function
console.log("init B instance")
}
}
Object.inherit(B, A);
var b = new B;
b.init();
>> init A instance
>> init B instance
b.say();
>> gav
inherit'у место в Function
При таком использовании, как в примере выше, ему место в отдельном неймспейс-объекте
Если честно, то не хотелось городить отдельный namespace `Class` только ради одной функции. А до `Object` быстрее «дотянутся». Я понимаю, что в будущих версиях языка могу ввести стандартную `Object.inherit` и это поведение сломается, но я регулярно просматриваю ES.Next и пока ничего подобного там не вижу.
Добро пожаловать в клуб: habrahabr.ru/blogs/javascript/132698/#comment_4404597
Как-то недавно я смотрел сколько у меня занимает инициализация классов.
Она у меня была чуть более сложная чем у вас.
Что я могу сказать — получилось где-то 100мсек исключительно чтобы собрать хитрые классы.
Это не позволительно много.
У Вас примерно таже проблема — очень долго будут собираться классы при подключении скрипта.
Она у меня была чуть более сложная чем у вас.
Что я могу сказать — получилось где-то 100мсек исключительно чтобы собрать хитрые классы.
Это не позволительно много.
У Вас примерно таже проблема — очень долго будут собираться классы при подключении скрипта.
Ваш код, это реальный ад :)
Зачем такие сложности? Зачем нужен stat? Почему не использовать прототипное наследование?
Совсем не ясно какие плюсы дает ваша реализиация?
С ее помощью проще создавать классы? Нет, только сложнее.
Меньше писать кода? Нет, кода получается на порядок больше чем надо.
В общем не ясно зачем все это.
В коде весьма сложно разобраться, но вот несколько моментов:
1.
Можно проще
2.
Статические функции и данные в динамическом языке… сильно ;)
3.
Противоречит принципам ООП. Если метод(свойство) есть в классе, то он должен быть во всех его потомках. То что вы пытаетесь сделать — это член класса, и в этом случае добавляется в класс (его конструктор), а не в его прототип.
4.
Правда ожидаете исключение? delete его не вызывает, и всегда возвращает true, даже когда свойство не было удалено. Единственный момент, что в IE6 выбрасывается исключении при попытке удалить некоторые свойства объекта window… но вы явно этого здесь не делаете, да и вряд ли ориентируeтесь на IE6.
5.
6.
callee и caller — не кроссбраузерны, и запрещены в strict mode. Считайте что этих свойств нет у функций, для вашего же блага.
7.
Достигается подобное так
Но это все плохая идея, потому что:
Поэтому лучше явно вызывать construct или любой другой метод у супер класса
И это касается любого метода.
8.
Это вы выполняете роль прототипного наследования. На подобных вызовах вы будете терять огромное количество времени.
Правильный подход (кратко, pure js)
Да, немного длиннее, но на порядки быстрее.
И далее далее…
Поизучайте подобные реализации в различных популярных фреймворках и библиотеках. В большинстве случаев, их конструктор классов на самом деле упрощает конструирование и использование классов.
Зачем такие сложности? Зачем нужен stat? Почему не использовать прототипное наследование?
Совсем не ясно какие плюсы дает ваша реализиация?
С ее помощью проще создавать классы? Нет, только сложнее.
Меньше писать кода? Нет, кода получается на порядок больше чем надо.
В общем не ясно зачем все это.
В коде весьма сложно разобраться, но вот несколько моментов:
1.
child.statConstructor.prototype.proto = function() {
return;
}
Можно проще
child.statConstructor.prototype.proto = Function()
// вместо
if (parent && ("statConstructor" in parent) && parent.statConstructor && typeof (parent.statConstructor) === "function") { ... }
// достаточно
if (parent && typeof parent.statConstructor == "function") { ... }
2.
* У классов есть параметр stat, предназначенный для статических ф-ий и данных.
Статические функции и данные в динамическом языке… сильно ;)
3.
* Можно запретить наследовать метод, объявляя его без prototype.
Противоречит принципам ООП. Если метод(свойство) есть в классе, то он должен быть во всех его потомках. То что вы пытаетесь сделать — это член класса, и в этом случае добавляется в класс (его конструктор), а не в его прототип.
4.
try {
delete child.stat[name];
} catch(e) {
}
Правда ожидаете исключение? delete его не вызывает, и всегда возвращает true, даже когда свойство не было удалено. Единственный момент, что в IE6 выбрасывается исключении при попытке удалить некоторые свойства объекта window… но вы явно этого здесь не делаете, да и вряд ли ориентируeтесь на IE6.
5.
if(child.stat.construct) {
// Вызывается при создании класса или создании потомка без stat.construct
child.stat.construct();
}
// уж лучше так
if(typeof child.stat.construct == 'function') {
// Вызывается при создании класса или создании потомка без stat.construct
child.stat.construct();
}
6.
arguments.callee.caller
callee и caller — не кроссбраузерны, и запрещены в strict mode. Считайте что этих свойств нет у функций, для вашего же блага.
7.
А мне хочется, чтобы все объекты, наследники класса Foo имели уникальный id и предупреждали пользователя, что умеют взрываться.
Для реализации этого — я создаю специальный метод cnstruct (constructor — уже занято), и выполняю его при создании каждого объекта. Чтобы не забыть его выполнять, отказываюсь от создания объектов через new Foo() и создаю объекты через статический метод Foo.stat.create().
Достигается подобное так
function createClass(super, ext){
if (!super)
super = Function();
var superConstruct = super.prototype.cunstruct;
var newClass = function(){
if (typeof superConstruct == 'function')
superConstruct.apply(this, arguments)
if (typeof this.construct == 'function')
this.construct.apply(this, arguments);
}
var tempClass = Function();
tempClass.prototype = super.prototype;
newClass.prototype = new tempClass();
for (var key in ext)
newClass.prototype[key] = ext[key];
return newClass;
}
Но это все плохая идея, потому что:
- Иногда не нужно вызывать инициализирующую часть супер класса
- Часто нужно управлять порядком инструкций, что-то делать до вызова инициализирующей части супер класса, а что-то после
- Класс потомок, может получать другой набор параметров в конструктор, который отличается от набора супер класса
Поэтому лучше явно вызывать construct или любой другой метод у супер класса
var Foo = function(a, b){ .. }
var Bar = function(c, a){
// делаем что-то до
Foo.call(this, a, 'contant value');
// Делаем что-то после
}
Bar.prototype = new Foo();
И это касается любого метода.
8.
child.prototype.protoFunc = child.statConstructor.prototype.protoFunc = function(callerFuncName, args, applyFuncName) {
/*
* Позволяет вызвать функцию более ранней версии в иерархии прототипов ...
Это вы выполняете роль прототипного наследования. На подобных вызовах вы будете терять огромное количество времени.
Правильный подход (кратко, pure js)
var Foo = function(){};
Foo.prototype = {
method: function(){ .. }
};
var Bar = function(){};
Bar.prototype = new Foo();
Bar.prototype.method = function(){
Foo.prototype.method.apply(this, arguments);
}
Да, немного длиннее, но на порядки быстрее.
И далее далее…
Поизучайте подобные реализации в различных популярных фреймворках и библиотеках. В большинстве случаев, их конструктор классов на самом деле упрощает конструирование и использование классов.
Вот примерно таких разгромных комментариев и ожидал. Даже обиделся, что ни кто не обвиняет по существу. Особенно ждал нападок на медленную реализацию protoFunc, но об отсутствии caller.calle в strict mode — не догадывался. В общем огромное спасибо за такой развернутый комментарий. Пошел серьезно пересматривать свои привычки.
Sign up to leave a comment.
Мой extend и стиль наследования классов