Немного магический способ наследования
Не люблю использовать всякие обертки, типа
Constr = Constructor( Parent, function() {});
Не нравится и то, что во многих реализациях наследования, функция, отвечающая за него пишется под конструктором:
Constr = function() {
// ...много кода
}
inherit( Constr, Parent );
Из-за этого приходится скроллить вниз, дабы посмотреть, наследует ли конструктор свойства другого конструктора. Хотелось бы использовать обычные, традиционные функции-конструкторы, но с кратким и очевидным наследованием, определенным в начале функции:
Constr = function() {
inherit( this, Parent );
// ... много кода
}
Мне кажется это красивым и удобным (а используя defineProperty можно добиться еще большей лаконичности и писать this.inherit( Parent )). Немного магии:
var inherit = function( object, Parent ) {
var args = Array.prototype.slice.call( arguments, 2 ),
proto = object.__proto__;
Parent.apply( object, args );
if( proto.__proto__.constructor !== Parent ) {
proto.__proto__ = applyConstruct( Parent, args );
}
}
var applyConstruct = function( Constructor, args ) {
var argNames = [];
for( var i = 0; i < args.length; i++ ) {
argNames.push( 'arg' + i );
}
argNames.join( ',' );
return new Function( argNames, 'return new this( ' + argNames + ' );' ).apply( Constructor, args );
}
C1 = function C1() {
this.a = 1;
this.b = 12;
};
C1.prototype = {
m1: function() {
// 11
},
m2: function() {
// 12
}
};
C2 = function C2() {
inherit( this, C1 );
this.b = 22;
this.c = 23;
};
C2.prototype = {
m2: function() {
// 22
},
m3: function() {
// 23
}
};
C3 = function C3() {
inherit( this, C2 );
this.c = 33;
this.d = 4;
};
C3.prototype = {
m3: function() {
// 33
},
m4: function() {
// 34
}
};
Здесь используется свойство __proto__, которое не поддерживается даже новыми ИЕ. В дальнейшем постараюсь избавиться от этого свойства, но появится небольшая избыточность:
Constr = function() {
inherit( this, Constr, Parent );
// ... много кода
}
Хотя еще не представляю, как добиться этого. В этой теме http://javascript.ru/forum/misc/3127...nstructor.html было выяснено, что prototype нельзя переопределить после инициализации экземпляра конструктора. |
Очень топорный вариант:
var inherit = function( object, Child, Parent ) {
var args = Array.prototype.slice.call( arguments, 3 );
Parent.apply( object, args );
extendPrototype( Child.prototype, Parent.prototype );
}
var extendPrototype = function( o1, o2 ) {
for( var i in o2 ) {
o1[i] = o1[i] || o2[i];
}
};
var Constructor = function() {
inherit( this, Constructor, Parent )
}
Здесь не будет работать instanceof. |
Цитата:
имя_экзэмпляра.метод а через имя_экзэмпляра.constructor.prtototype.method |
Цитата:
В общем, проведя двое суток над этой задачей, так и не нашел решения. Придется использовать старый дедовский способ наследования, определенного после прототипа. За то можно наследовать сразу несколько конструкторов, так как это неотъемлемая особенность прототипного программирования.
Function.prototype.extendNotEnum( 'inherits', function( Parent ) {
var prototype = this.prototype;
this.prototype = Object.create( Parent.prototype );
this.prototype.constructor = this;
this.prototype.extend( prototype );
});
// методы extend и extendNotEnum — кастомные. Первый добавляет новые свойства в контекст, второй делает то же самое, но с enumerable: false
Child = function(){
Parent.apply( this, arguments )
}
Child.prototype = {}
Child.inherits( Parent );
|
| Часовой пояс GMT +3, время: 05:55. |