03.10.2011, 10:49
|
|
Просто любитель
|
|
Регистрация: 13.09.2011
Сообщений: 300
|
|
Prototype. Одноблочное определение псевдокласса. Литеральная форма не робит. Почему?
Мне не очень нравятся многоблочные определения псевдоклассов. Т.е. когда вначале определяют класс, блок закрывают, а затем определяют его прототип. Я решил попробовать определить прототип прямо в блоке класса. И столкнулся с полтергейстом: Создан простой класс, в котором есть прототипная переменная, общая для всех экземпляров класса. Вызывается, через один экземпляр, функция, которая увеличивает общую переменную на 1. Затем выводится значение общей переменной для другого экземпляра.
<html><body>
<script>
function Test()
{
Test.prototype.data=1;
Test.prototype.f=function()
{
Test.prototype.data++;
}
}
test1=new Test;
test2=new Test;
test1.f();
document.write("test2.data=",test2.data,"<br>");
</script>
Всё верно, общая переменная поменялась — выводит: test2.data=2.
Отлично! Пробуем оптимизировать:
<html><body>
<script>
function Test()
{
Test.prototype=
{
data:1,
f:function()
{
Test.prototype.data++;
}
}
}
test1=new Test;
test2=new Test;
test1.f();
document.write("test2.data=",test2.data,"<br>");
</script>
Получаем: Uncaught TypeError: Object #<Test> has no method 'f'. WTF?!!
А если так:
<html><body>
<script>
function Test(){}
Test.prototype=
{
data:1,
f:function()
{
Test.prototype.data++;
}
}
test1=new Test;
test2=new Test;
test1.f();
document.write("test2.data=",test2.data,"<br>");
</script>
То работает! Но опять разбиваем на два блока верхнего уровня =(.
Вопросы:- Почему литеральная запись объекта внутри блока определения класса не работает, но работает присвоение там же но по полям? (Кстати с with внутри класса тоже не робит). Чем отличается присвоение по полям от литеральной записи?
- Почему, в таком случае, литеральная запись работает вне блока определения класса?
Поясните, кто знает механику работы объектов, я что-то не догоняю.
|
|
03.10.2011, 11:41
|
|
Рассеянный профессор
|
|
Регистрация: 06.04.2009
Сообщений: 2,379
|
|
Когда во втором примере ты пишешь:
Сообщение от GuardCat
|
test1=new Test;
|
this.__proto__ внутри конструктора начинает ссылаться на Test.prototype. А дальше ты бац и заменяешь Test.prototype на новый объект, но this.__proto__ по-прежнему ссылается на старый объект, в котором метода f нет. Вот в ошибке и написано, что его нет. В первом примере ты изменяешь уже существующий объект, и т. к. на него ссылаются и this.__proto__ и Test.prototype, изменения видны в обоих.
Сообщение от GuardCat
|
Мне не очень нравятся многоблочные определения псевдоклассов. Т.е. когда вначале определяют класс, блок закрывают, а затем определяют его прототип
|
прототип будет .... , короче, не надо так, бяка.
Последний раз редактировалось Riim, 03.10.2011 в 11:45.
|
|
03.10.2011, 11:52
|
|
Просто любитель
|
|
Регистрация: 13.09.2011
Сообщений: 300
|
|
Спасибо, Riim. Стало понятнее. Про бяку, раскройте тему, пожалуйста.
Вы имеете ввиду, что не следует определять прототип литерально, заменяя объект на свой (это теперь понятно)?
Тогда вопрос, внутри определения класса можно (не бяка ли) трогать прототип за поля, не заменяя объект или нужно делать это за пределами определения класса?
Или вообще размещать переменные в прототипе моветон и надо использовать поля класса?
Пристрелите во мне быдлокодера =)
Последний раз редактировалось GuardCat, 03.10.2011 в 12:21.
|
|
03.10.2011, 12:40
|
|
Рассеянный профессор
|
|
Регистрация: 06.04.2009
Сообщений: 2,379
|
|
Сообщение от GuardCat
|
внутри определения класса можно (не бяка ли) трогать прототип за поля
|
конечно можно, просто то, что более-менее статично лучше определить один раз, так оно будет общее для всех экземпляров. А то, что определяется внутри конструктора, создается каждый раз, а это расход памяти, теряется одно из преимуществ прототипного ООП над обычным.
Сообщение от GuardCat
|
Мне не очень нравятся многоблочные определения псевдоклассов. Т.е. когда вначале определяют класс, блок закрывают, а затем определяют его прототип
|
а так вообще все много-много раз создается.
Последний раз редактировалось Riim, 03.10.2011 в 12:42.
|
|
03.10.2011, 12:51
|
Новичок на форуме
|
|
Регистрация: 19.02.2008
Сообщений: 9,177
|
|
Сообщение от GuardCat
|
Мне не очень нравятся многоблочные определения псевдоклассов. Т.е. когда вначале определяют класс, блок закрывают, а затем определяют его прототип.
|
https://github.com/Kolyaj/CrossJS/bl...unction.js#L97
var MyClass = AnotherClass.inherit({
constructor: function() {
MyClass.superclass.constructor.apply(this, arguments);
this.a = 5;
},
method1: function() {
alert('method1');
},
method2: function() {
alert('method2');
}
});
|
|
03.10.2011, 13:18
|
|
Просто любитель
|
|
Регистрация: 13.09.2011
Сообщений: 300
|
|
Сообщение от Riim
|
...
а так вообще все много-много раз создается.
|
Вкурил. И правда, на то он и конструктор.
Kolyaj, спасибо. Только я не настолько крут пока, чтобы понять, что происходит в библиотеке, даже несмотря на комментарии. Сохранил. Буду разбираться.
|
|
03.10.2011, 13:46
|
|
Рассеянный профессор
|
|
Регистрация: 06.04.2009
Сообщений: 2,379
|
|
Сообщение от Riim
|
теряется одно из преимуществ прототипного ООП над обычным
|
кстати, а это действительно преимущество? А то я где-то мельком услышал, что в обычном ООП все для экземпляра каждый раз создается, в том числе то, что вне конструктора описано. Сейчас вот подумал, а что мешает в обычном ООП сделать механизм подобный тому, что в js? Кто-нибудь знает?
|
|
|
|