Показать сообщение отдельно
  #6 (permalink)  
Старый 01.07.2009, 19:15
Аватар для Riim
Рассеянный профессор
Отправить личное сообщение для Riim Посмотреть профиль Найти все сообщения от Riim
 
Регистрация: 06.04.2009
Сообщений: 2,379

1. Можно расширять/урезать prototype конструктора, тем самым расширяя/урезая все созданные им экземпляры. Проблема в том, что в один момент времени все экземпляры будут либо с расширенной функциональностью, либо с урезанной, а нужно и то и другое, т. к. в один момент могут быть окна как с уже загруженным содержимым, так и с не загруженным. Да и вообще, так, как-то неправильно.

2. Хочется как-то так (псевдокодом):
// класс с базовой функциональностью
var BaseMethods = Class.create({
	method1: function() {}
});

// класс с расширенной функциональностью, наследующий от BaseMethods
var ExMethods = Class.create(BaseMethods, {
	method2: function() {}
});

// класс создающий окно, пока наследует от BaseMethods
var Window = Class.create(BaseMethods, {
	initialize: function() {},

	extendFunctional: function() {
		// после вызова этого метода у экземпляра, он (экземпляр) меняется так, как будто создавший его класс наследует от ExMethods
	}
});

// создаем окно
var w1 = new Window(p1, p2, ...);

// и далее при загрузке содержимого
w1.extendFunctional();


Но так не получится, и хорошо, а то, какое-то кривое OOP. Дело в том, что экземпляр - это примерно такая конструкция (схематично):
Object {
__proto__: {}
}
где Object.__proto__ это Function.prototype у конструктора:
Function {
prototype: {}
}
так вот Function.prototype можно свободно редактировать (см. пункт 1), а вот Object.__proto__ , никак. Единственный способ указать, куда должен вести Object.__proto__ , это создать его функцией-конструктором, при этом создается именно новый объект, т. е. нельзя дать конструктору объект и сказать: "создай не новый объект с __proto__ , а меняй __proto__ вот у этого".

3. Раз в предыдущем пункте создается именно новый объект, то получается, что во время загрузки окну соответствует один экземпляр, а после загрузки, другой. По-моему это какое-то кривое OOP. Если уж к созданному окну прикрепляется какой-то экземпляр, то именно он и должен оставаться за ним. Если все же очень хочется так, то проблема в том, что ссылка на старый экземпляр много где сохранена и ее нужно везде заменить на новую. Тут можно сохранять не ссылку, а объект, содержащий в свойстве эту ссылку и при смене этого свойства в любом месте программы, изменения произойдут везде, где объект, содержащий ссылку, сохранен.

4. Извращаемся дальше. Во время загрузки теперь временное окно, которому соответствует один экземпляр, далее оно заменяется на такое же и новому окну соответствует другой экземпляр. Теперь вполне правильное OOP. Основная проблема тут следующая (она и для пункта 3 тоже есть):
создали всю эту систему, все работает, и вот хотим написать расширяющий модуль. Этот модуль что-то записывает в экземпляр для временного окна, т. е. что-то запоминает там. Далее при замене экземпляра все запомненное должно переписаться в новый экземпляр. Мы знаем, что именно запоминает расширяющий модуль и, зная имена этих ключей, можем просто переписать их, обращаясь по именам при создании нового экземпляра. Но тут получится, что базовая система будет подстраиваться под конкретный расширяющий ее модуль. Думаю не надо объяснять, почему это не правильно. Можно продумать все, так что бы базовая система подстраивалась не под конкретный расширяющий модуль, а под все будущие модули, и это уже будет вполне правильно. Как? Можно, например, выдумать что-нибудь с callback-ом, запускающимся при создании экземпляра для постоянного окна (callback конечно уже в расширяющем модуле определяется) или во временном экземпляре создать определенное свойство содержащее объект и обязать все модули запоминать все именно в этом объекте и далее просто перекидывать его целиком в новый экземпляр. Но если продумывать дальше, то все это лишь создает новые проблемы.

5. Вариант получше. Весь функционал есть сразу, но часть не очень-то хочет работать (псевдокодом):
var Window = Class.create({
	contentLoaded: false,
	method2: function() {
		if (!this.contentLoaded) return false;
		// ....
	}
});


6. Вроде самый правильный вариант. Я не знаю, зачем вы придумывали все написанное выше (по крайней мере, я предположил, прочтя ТС, что вы мыслили примерно так) когда все вроде совсем очевидно:

var Window = Class.create({
	method1: function() {},

	extendFunctional: function($super) {
		// точно не помню куда там $super указывает, если на Function.prototype, то так:
		Object.extend(this, $super.constructor.ExMethod);

		// если на Function:
		Object.extend(this, $super.ExMethod);

		// или проще всего:
		Object.extend(this, Window.ExMethod);
	}
});

Window.ExMethod = {
	method2: function() {}
};

// создаем окно
var w1 = new Window(p1, p2, ...);

// и далее при загрузке содержимого
w1.extendFunctional();


Вариант вроде того:

extendFunctional: function($super) {
		Object.extend(this, {
			method2: function() {}
		});
	}

плох тем, что method2 будет создаваться постоянно, и тем самым будет забивать память.

upd: для тех, кто любит придираться к мелочам: во всем посте Function, нужно понимать не как window.Function, а как конструктор класса. Object в некоторых случаях нужно понимать как экземпляр класса.

Последний раз редактировалось Riim, 01.07.2009 в 19:27.
Ответить с цитированием