Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 30.06.2009, 19:41
Интересующийся
Отправить личное сообщение для phprus Посмотреть профиль Найти все сообщения от phprus
 
Регистрация: 29.07.2007
Сообщений: 13

Возможна ли смена типа созданного объекта в Javascript?
Есть система в которой активно используются классы, созданные с помощью библиотеки prototype. Классы могут быть унаследованы друг от друга.
К примеру существует такая иерархия:
var Animal = Class.create({
  initialize: function(name) {
    this.name  = name;
  }
});

// subclassing Animal
var Snake = Class.create(Animal, {
  initialize: function($super, name) {
    $super(name); // вызывается всегда в самом начале конструктора производного класса
    this.len = 5; // дополнительные свойства. (этот код можно вынести в отдельную функцию и вызывать позже)
  },
  speak: function() {
    alert(this.name + " says: hissssssssss, len: " + this.len);
  }
});

В коде создается переменная типа Animal:
var a = new Animal('test Animal');

и добавляется во всякие разные массивы.

Подскажите пожалуйста, можно ли у этой переменной сменить тип на Snake так, что-бы у переменной "а" появились свойства и методы из класса Snake?
Ответить с цитированием
  #2 (permalink)  
Старый 30.06.2009, 20:18
Аватар для Riim
Рассеянный профессор
Отправить личное сообщение для Riim Посмотреть профиль Найти все сообщения от Riim
 
Регистрация: 06.04.2009
Сообщений: 2,379

А зачем?
Ответить с цитированием
  #3 (permalink)  
Старый 30.06.2009, 20:39
Интересующийся
Отправить личное сообщение для phprus Посмотреть профиль Найти все сообщения от phprus
 
Регистрация: 29.07.2007
Сообщений: 13

На самом деле базовый класс реализует некое окно, а производные окна с дополнительной функциональностью (в первом приближении они отличаются только текстом внутри). Проблема в том, что при создании нового окна его код может быть еще не подгружен, а хотелось бы показать пользователю созданное окошко внутри которого к примеру разместить какой-либо индикатор на время загрузки.
Можно конечно временное окно убирать, а когда подгрузится код создавать на его месте постоянное, но тогда возникнут некоторые проблемы с тем что переменная со старым классом окном уже попала в другие участки кода, положение DIV'а, который создается окном в DOM-дереве тоже имеет значение и по этому все это придется отслеживать. Да и придется дополнительно различать временные и не временные окна при обработке просто списка окон.

Я думаю, что если возможно то, что я хочу, то это может оказаться несколько проще чем замена одного окна на другое, по этому и задаю такой странный вопрос.
Ответить с цитированием
  #4 (permalink)  
Старый 30.06.2009, 22:00
Аватар для Riim
Рассеянный профессор
Отправить личное сообщение для Riim Посмотреть профиль Найти все сообщения от Riim
 
Регистрация: 06.04.2009
Сообщений: 2,379

Есть окно. Просто окно, не временное. В нем loadIndicator. Как текст загрузился, убираем индикатор и добавляем текст. Окну соответствует экземпляр класса и при добавлении текста функциональность этого экземпляра должна расшириться.

Такое понимание проблемы подойдет?
Ответить с цитированием
  #5 (permalink)  
Старый 01.07.2009, 10:48
Интересующийся
Отправить личное сообщение для phprus Посмотреть профиль Найти все сообщения от phprus
 
Регистрация: 29.07.2007
Сообщений: 13

Сообщение от Riim Посмотреть сообщение
Есть окно. Просто окно, не временное. В нем loadIndicator. Как текст загрузился, убираем индикатор и добавляем текст. Окну соответствует экземпляр класса и при добавлении текста функциональность этого экземпляра должна расшириться.

Такое понимание проблемы подойдет?
да. Это то, что мне нужно. Функциональность тоже подгружается, но думаю что на суть проблемы это не влияет.
Ответить с цитированием
  #6 (permalink)  
Старый 01.07.2009, 18: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 в 18:27.
Ответить с цитированием
  #7 (permalink)  
Старый 01.07.2009, 19:07
Интересующийся
Отправить личное сообщение для phprus Посмотреть профиль Найти все сообщения от phprus
 
Регистрация: 29.07.2007
Сообщений: 13

Спасибо за столь подробный рассказ!

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

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

// и далее при загрузке содержимого
w1.extendFunctional();
Вы правы, я рассуждал именно таким образом.

Скажите пожалуйста, а в данном решении дополнительные методы появятся только у экземпляра w1? Те можно ли разным экземплярам класса Window назначать разные дополнительные методы?
Ответить с цитированием
  #8 (permalink)  
Старый 01.07.2009, 23:31
Аватар для Riim
Рассеянный профессор
Отправить личное сообщение для Riim Посмотреть профиль Найти все сообщения от Riim
 
Регистрация: 06.04.2009
Сообщений: 2,379

Сообщение от phprus
Скажите пожалуйста, а в данном решении дополнительные методы появятся только у экземпляра w1?
Да.

Сообщение от phprus
Те можно ли разным экземплярам класса Window назначать разные дополнительные методы?
Методу extendFunctional передаете параметр и в зависимости от него расширяете тем или иным объектом.
Ответить с цитированием
  #9 (permalink)  
Старый 02.07.2009, 15:33
Интересующийся
Отправить личное сообщение для phprus Посмотреть профиль Найти все сообщения от phprus
 
Регистрация: 29.07.2007
Сообщений: 13

Спасибо!
Ответить с цитированием
  #10 (permalink)  
Старый 04.07.2009, 01:41
Аватар для x-yuri
Отправить личное сообщение для x-yuri Посмотреть профиль Найти все сообщения от x-yuri
 
Регистрация: 27.12.2008
Сообщений: 4,201

Сообщение от phprus
Те можно ли разным экземплярам класса Window назначать разные дополнительные методы?
а может не стоит? Может лучше загрузить весь функционал, или загрузка тормозит именно из-за функционала?
Ответить с цитированием
Ответ



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

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