Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 01.09.2012, 02:13
Аватар для FINoM
Новичок
Отправить личное сообщение для FINoM Посмотреть профиль Найти все сообщения от FINoM
 
Регистрация: 05.09.2010
Сообщений: 2,298

Немного магический способ наследования
Не люблю использовать всякие обертки, типа
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 );
 // ... много кода
}


Хотя еще не представляю, как добиться этого. В этой теме Почему не работает код? Вопрос о this.constructor. было выяснено, что prototype нельзя переопределить после инициализации экземпляра конструктора.
__________________
"Matreshka is fucking awesome" © чувак с Reddit
Matreshka.js - Три возможности

Последний раз редактировалось FINoM, 01.09.2012 в 02:19.
Ответить с цитированием
  #2 (permalink)  
Старый 01.09.2012, 02:35
Аватар для FINoM
Новичок
Отправить личное сообщение для FINoM Посмотреть профиль Найти все сообщения от FINoM
 
Регистрация: 05.09.2010
Сообщений: 2,298

Очень топорный вариант:

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.
__________________
"Matreshka is fucking awesome" © чувак с Reddit
Matreshka.js - Три возможности
Ответить с цитированием
  #3 (permalink)  
Старый 01.09.2012, 08:19
Аватар для Dim@
Профессор
Отправить личное сообщение для Dim@ Посмотреть профиль Найти все сообщения от Dim@
 
Регистрация: 21.04.2012
Сообщений: 951

Сообщение от FINoM
было выяснено, что prototype нельзя переопределить после инициализации экземпляра конструктора
нет, можно просто если он станет переопределён после экземпляра конструктора, то будут мутени с instanceof и ещё с чем нибудь - к новым методам придётся обращаться не через
имя_экзэмпляра.метод

а через
имя_экзэмпляра.constructor.prtototype.method
Ответить с цитированием
  #4 (permalink)  
Старый 02.09.2012, 04:33
Аватар для FINoM
Новичок
Отправить личное сообщение для FINoM Посмотреть профиль Найти все сообщения от FINoM
 
Регистрация: 05.09.2010
Сообщений: 2,298

Сообщение от Dim@
имя_экзэмпляра.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 );
__________________
"Matreshka is fucking awesome" © чувак с Reddit
Matreshka.js - Три возможности
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск