Модераторы: Sardar, Aliance
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Наследование и сво-во "constructor" 
V
    Опции темы
Се ля ви
Дата 3.6.2008, 15:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Java/SOAрхитектор
****


Профиль
Группа: Модератор
Сообщений: 2016
Регистрация: 5.6.2004
Где: place without tim e and space

Репутация: 5
Всего: 127



Насколько я понял, наследование в JS реализуется за счёт того, что объект содержит в себе неявную ссылку на объект-предок в иерархии наследования (эта ссылка является явной для FF и называется "__proto__").

Но есть один нюанс: для объекта, расположенного по этой ссылке, должно выполняться требование, что его свойство "constructor" ссылается на функцию-конструктор объекта, а сам объект в случае необходимости получает ссылку на свой конструктор, как раз через эту самую неявную ссылку (в случае FF - явную - "__proto__"), вызывая свойство "constructor". Когда ScriptEngine не находит свойства "constructor" в объекте, она обращается к "__proto__" и пытается найти это свойство у объекта, расположенного по этому адресу.

Таким образом, если мы смотрим на это хозяйство из объекта, то для FF справедливо следующее:
Код
obj.__proto__ === obj.constructor.prototype

, так как на самом деле, поскольку
Код
obj.hasOwnProperty('constructor') == false;

, происходит следующее:
Код
obj.__proto__ === obj.__proto__.constructor.prototype

Для остальных же браузеров, получается, что из объекта мы можем увидеть прототип только воспользовавшись правой частью первого тождества. Если эта цепочка из двух (а с неявным - трёх) вызовов нарушится, то объект не сможет явно увидеть свой прототип.

Таким образом, когда мы производим наследование присвоением
Код
var childObj = new ChildObj(),
    parentObj = new ParentObj();

childObj.constructor.prototype = parentObj;

, то после этого получается вот что:
Код
childObj.__proto__ != childObj.constructor.prototype

, зато:
Код
childObj.constructor.prototype === parentObj.__proto__

, поскольку
Код
childObj.__proto__ === parentObj

и
Код
parentObj.hasOwnProperty('constructor') == false;

, так что фактически мы имеем следующее тождество:
Код
childObj.constructor === childObj.__proto__.__proto__.constructor

, т.е. мы потеряли связь с конструктором объекта "childObj"!

Авторы нескольких статей про JS-наследование специально указывают на этот момент и призывают после присвоения ссылке "prototype" объекта-предка присвоить ссылку на её "constructor":
Код
var childObj = new ChildObj(),
    parentObj = new ParentObj(),
    con = childObj.constructor,
    childObj.constructor.prototype = parentObj;
parentObj.constructor = con;

Да, таким образом мы восстановили ссылку на конструктор объекта "childObj", но проблему мы эту решили, создав себе другую - теперь для всех браузеров, кроме FF, мы потеряли ссылку на конструктор объекта "parentObj"! Ведь теперь:
Код
parentObj.hasOwnProperty('constructor') == true;

, так что
Код
parentObj.__proto__ != parentObj.constructor.prototype

И только в FF мы можем написать
Код
parentObj.__proto__.constructor

, а в остальных браузерах - кирдык. Думается, что использование длинных деревьев наследования обязательно спотыкнётся об это обстоятельство или по крайней мере создаст большие неудобства.

Вот, собственно, и проблема - как это ограничение модели можно было бы на ваш взгляд обойти?


--------------------
  )
 (
[_])
проф. блог

Кролики думали, что занимаются любовью, а на самом деле их просто разводили...
PM MAIL WWW Skype GTalk   Вверх
SelenIT
Дата 3.6.2008, 20:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


баг форума
****


Профиль
Группа: Завсегдатай
Сообщений: 3996
Регистрация: 17.10.2006
Где: Pale Blue Dot

Репутация: 49
Всего: 401



Если не ошибаюсь, именно эту путаницу некогда разруливал Zeroglif в своем "культовом" комменте к котеровской набле о наследовании в JS...


--------------------
Осторожно! Данный юзер и его посты содержат ДГМО! Противопоказано лицам с предрасположенностью к зонеризму!
PM MAIL   Вверх
Се ля ви
Дата 3.6.2008, 22:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Java/SOAрхитектор
****


Профиль
Группа: Модератор
Сообщений: 2016
Регистрация: 5.6.2004
Где: place without tim e and space

Репутация: 5
Всего: 127



SelenIT, да, Zeroglif там это объяснил, но лекарства не дал - пост заканчивается констатацией этого факта и вопрос, что с этим делать не поднял. Может быть, там будет про это дальше - сейчас почитаю тему, всё-таки пять листов после этого...


--------------------
  )
 (
[_])
проф. блог

Кролики думали, что занимаются любовью, а на самом деле их просто разводили...
PM MAIL WWW Skype GTalk   Вверх
AKS
Дата 4.6.2008, 07:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Участник форума
**


Профиль
Группа: Участник
Сообщений: 725
Регистрация: 20.9.2006

Репутация: 27
Всего: 52



Се ля ви, я дочитал вот до этого (дальше пока не стал читать - с утра голову надо беречь ;) ):
Цитата(Се ля ви @  3.6.2008,  15:46 Найти цитируемый пост)
childObj.constructor.prototype === parentObj.__proto__

Вы ведь чуть выше написали:
Цитата(Се ля ви @  3.6.2008,  15:46 Найти цитируемый пост)
childObj.constructor.prototype = parentObj;

Вы явно немного запутались. А начать "распутывать" можно с этого: childObj.constructor.prototype = parentObj. Вот зачем это?

PM MAIL   Вверх
Се ля ви
Дата 4.6.2008, 14:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Java/SOAрхитектор
****


Профиль
Группа: Модератор
Сообщений: 2016
Регистрация: 5.6.2004
Где: place without tim e and space

Репутация: 5
Всего: 127



Так, забудьте, что я тут до этого написал. Давайте начнём заново?

Я решил описать проблему в комментариях к коду. Комментариев получилось очень много, за то можно теперь весь этот текст загнать в редактор и, запустив в браузере (будет работать только в FF) понять, что всё работает именно так, как я расписываю.

Так же весьма рекомендую периодически по ходу чтения поглядывать в схемку, за которую большой "Thanks" Zeroglif`у.

Код
// *************** Часть первая: "Постановка проблемы"
// в которой ребёнок теряет свой конструктор.

// Реализация типичного наследования: 
var ChildObj = function () {},
    ParentObj = function (){},
    parentObj;

ChildObj.prototype = parentObj = new ParentObj();
    
var childObj = new ChildObj();

// И вот вопрос: как теперь, имея ссылку на childObj, получить ссылку на ChildObj,
// не пользуясь для этого особенностями реализации JavaScript в FF???

alert('childObj.constructor === ChildObj = ' + (
    childObj.constructor === ChildObj
)); // false - т.е. так мы нужную нам ссылку не получим.

// А куда же ссылается теперь наше свойство "constructor"?
// На самом деле оно ссылается уже на ParentObj: 
alert('childObj.constructor === ParentObj = ' + (
    childObj.constructor === ParentObj
));//true

// Почему? Потому что:
alert('childObj.hasOwnProperty(\'constructor\') = ' + (
    childObj.hasOwnProperty('constructor')
)); //false - т.е. в объекте нет ссылки на его конструктор

// По-этому, за неимением собственного, этот метод ищется
// по ссылке "__proto__": 
alert('childObj.__proto__ === parentObj = ' + (
    childObj.__proto__ === parentObj
));//true - т.е. он ищется в объекте, от которого мы унаследовались 

// Есть ли он там?
alert('parentObj.hasOwnProperty(\'constructor\') = ' + (
    parentObj.hasOwnProperty('constructor')
));//false - его и тут нету!

// Значит, в поисках свойства карабкаемся ещё дальше по иерархии
// свойств "__proto__" - делаем ещё один шаг:
alert('parentObj.__proto__.hasOwnProperty(\'constructor\') = ' + (
    parentObj.__proto__.hasOwnProperty('constructor')
)); //true - Ура! Наконец-то мы нашли "constructor"!

// Теперь зададимся вопросом - на что же ссылается свойство "__proto__"
// у parentObject`а? Элементарно - оно ссылается на
// ParentObject.prototype: 
alert('parentObj.__proto__ === ParentObj.prototype = ' + (
    parentObj.__proto__ === ParentObj.prototype
));//true - эта связь была установлена в момент создания parentObject

// Ну а так как ParentObject мы ни у кого не наследовали, то
alert('ParentObj.prototype.constructor === ParentObj = ' + (
    ParentObj.prototype.constructor === ParentObj
));//true

// Отматываем назад и следим за шагами ScriptEngine:
// Шаг 1: childObj.constructor ===
// Шаг 2: childObj.__proto__.constructor === parentObj.constructor ===
// Шаг 3: childObj.__proto__.__proto__.constructor === parentObj.__proto__.constructor === ParentObj.prototype.constructor === ParentObj

// Почему же так не получается с childObject`ом?
// Почему его свойство "__proto__" не ссылается на объект, который
// содержит свойство "constructor", ссылающееся на его конструктор - СhildObject?
// Потому, что мы ему при наследовании прототип заменили на parentObj и теперь
alert('childObj.constructor === parentObj.prototype = ' + (
    childObj.constructor === parentObj.constructor
));//true

//В отличие от parentObj, которому прототип не подменяли (не наследовали) и по-этому у него по ссылке
// "__proto__" остался его родной, автоматически созданный объект, содержащий "правильную" ссылку
// "constructor":
alert('parentObj.__proto__.hasOwnProperty(\'constructor\') = ' + (
    parentObj.__proto__.hasOwnProperty('constructor')
));//true
alert('parentObj.__proto__.constructor === ParentObj = ' + (
    parentObj.__proto__.constructor === ParentObj
));//true - чего childObj`а мы лишили в угоду наследования.

/* Итак, проблема: мы не можем, имея только ссылку на объект, в отношении которого произведено наследование
   (данным способом), получить ссылку на его конструктор.
   
   Теоретическая база: при создании объекта функции автоматически создаётся ещё один объект, которому
   назначается свойство "constructor", ссылающееся на этот самый объект функции, а функция ссылается на него
   через свойство "prototype". При создании объекта с помощью этого конструктора происходит присваивание
   obj.__proto__ = Obj.prototype, так что объект может найти свой конструктор по ссылке
   obj.__proto__.constructor. ScriptEngine при вызове свойства объекта в случае, если его не находит,
   совершает восхождение по ссылкам "__proto__" этого объекта, пока не найдёт нужное свойство, либо не упрётся
   в null (Object.prototype.__proto__ == null) - тогда возбуждается исключение.
   Всё хорошо работает до тех пор, пока мы не решаем использовать этот механизм для наследования. При
   наследовании мы ещё до создания экземпляра объекта присваеваем свойству "prototype" конструктора объекта
   ссылку на объект родителя. Этот объект замещает тот объект, который был автоматически создан при создании
   объекта функции, но, в отличие от него, не содержит обратной ссылки на конструктор - т.е. на этот объект
   функции. В итоге ссылка на конструктор теряется...
   
   В случае с тремя шагами наследования мы получим для внука конструктор дедушки, четырёх - прадедушки и т.д.
*/

// ******************* Часть вторая: "Попытка решить проблему влоб"
// в которой у родителя отбирают его конструктор и вручают конструктор его ребёнка вместо его конструктора

// Что же можно сделать?
// Напрашивается следующее: раз мы при наследовании подставляем свойству "prototype" конструктора новое
// значение, не имеющее ссылки "constructor", взамен старого, имевшего это свойство, то почему бы нам не
// присвоить этому объекту это свойство принудительно, что бы изначальное соглашение продолжало выполняться?

// Давайте так и сделаем:
parentObj.constructor = ChildObj;
// мы это можем сделать сразу же, следующим шагом после реализации наследования, когда у нас ссылка
// на ChildObj ещё под носом. Можем даже, воспользовавшись тем, что любое присваивание возвращает
// присваиваемый результат, сделать такое заплаточное наследование одним действием:
// (СhildObj.prototype = parentObj = new ParentObj()).constructor = ChildObj;

//Вуаля! Мы решили проблему:
alert('childObj.constructor === ChildObj = ' + (
    childObj.constructor === ChildObj
)); // теперь - true - Победа!

// После того, как побегали, попрыгали, покидали шапки в воздух и натанцевались вдоволь,
// давайте подумаем - какой ценой нам эта победа досталась?
// Очень даже большой! Теперь мы нарушили соглашение для значения ссылки "prototype" у объекта ParentObj:
alert('parentObj.constructor === ParentObj = ' + (
    parentObj.constructor === ParentObj
));//false... Что же мы наделали? Т.е. теперь ребёнок нашёл, а родитель - потерял свой конструктор!

// А куда же теперь ссылается конструктор родителя?
alert('parentObj.constructor === ChildObj = ' + (
    parentObj.constructor === ChildObj
));//true - вот куда он ссылается - на конструктор своего ребёнка. Почему?

// Просто раньше у нашего объекта parentObj отсутствовало свойство "constructor" и когда мы его вызывали,
// в отсутсвии этого свойства у него вызывалось свойство "__proto__" и у него уже вызывалось свойство
// "constructor". Это выражение на самом деле верно по-прежнему:
alert('parentObj.__proto__.constructor === ParentObj = ' + (
    parentObj.__proto__.constructor === ParentObj
));//true

// Но теперь нарушилась неявная цепочка вызова, ведь больше не выполняется равенство
alert('parentObj.constructor === parentObj.__proto__.constructor = ' + (
    parentObj.constructor === parentObj.__proto__.constructor
));//false - а раньше, до нашего этого решения, оно выполнялось и - всё с parentObj было в порядке!

// Т.е. решение не годится, если мы конечно, признаём, что каждый объект в цепочке наследования должен иметь
// возможность получить ссылку на свой конструктор.


Пока расписывал, нащупал решение проблемы и сейчас его тестирую. Как решу - напишу сюда. В любом случае получилось на мой взгляд весьма познавательное чтиво для тех, кто не очень хорошо разобрался в тонкостях реализации наследования в ECMAScript.


--------------------
  )
 (
[_])
проф. блог

Кролики думали, что занимаются любовью, а на самом деле их просто разводили...
PM MAIL WWW Skype GTalk   Вверх
Се ля ви
Дата 4.6.2008, 17:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Java/SOAрхитектор
****


Профиль
Группа: Модератор
Сообщений: 2016
Регистрация: 5.6.2004
Где: place without tim e and space

Репутация: 5
Всего: 127



Завершил и проблема решилась. В ближайшее время переработаю это в нормальную статью.

Вот полный вариант, изабильно снабжённый комментариями (фактически, это и есть статья из комментариев со вставками кода):
Код
// *************** Часть первая: "Постановка проблемы"
// в которой ребёнок теряет свой конструктор.

// Реализация типичного наследования: 
var ChildObj = function () {},
    ParentObj = function (){},
    parentObj;

ChildObj.prototype = parentObj = new ParentObj;
    
var childObj = new ChildObj;

// И вот вопрос: как теперь, имея ссылку на childObj, получить ссылку на ChildObj,
// не пользуясь для этого особенностями реализации JavaScript в FF???

alert('childObj.constructor === ChildObj = ' + (
    childObj.constructor === ChildObj
)); // false - т.е. так мы нужную нам ссылку не получим.

// А куда же ссылается теперь наше свойство "constructor"?
// На самом деле оно ссылается уже на ParentObj: 
alert('childObj.constructor === ParentObj = ' + (
    childObj.constructor === ParentObj
));//true

// Почему? Потому что:
alert('childObj.hasOwnProperty(\'constructor\') = ' + (
    childObj.hasOwnProperty('constructor')
)); //false - т.е. в объекте нет ссылки на его конструктор

// По-этому, за неимением собственного, этот метод ищется
// по ссылке "__proto__": 
alert('childObj.__proto__ === parentObj = ' + (
    childObj.__proto__ === parentObj
));//true - т.е. он ищется в объекте, от которого мы унаследовались 

// Есть ли он там?
alert('parentObj.hasOwnProperty(\'constructor\') = ' + (
    parentObj.hasOwnProperty('constructor')
));//false - его и тут нету!

// Значит, в поисках свойства карабкаемся ещё дальше по иерархии
// свойств "__proto__" - делаем ещё один шаг:
alert('parentObj.__proto__.hasOwnProperty(\'constructor\') = ' + (
    parentObj.__proto__.hasOwnProperty('constructor')
)); //true - Ура! Наконец-то мы нашли "constructor"!

// Теперь зададимся вопросом - на что же ссылается свойство "__proto__"
// у parentObject`а? Элементарно - оно ссылается на
// ParentObject.prototype: 
alert('parentObj.__proto__ === ParentObj.prototype = ' + (
    parentObj.__proto__ === ParentObj.prototype
));//true - эта связь была установлена в момент создания parentObject

// Ну а так как ParentObject мы ни у кого не наследовали, то
alert('ParentObj.prototype.constructor === ParentObj = ' + (
    ParentObj.prototype.constructor === ParentObj
));//true

// Отматываем назад и следим за шагами ScriptEngine:
// Шаг 1: childObj.constructor ===
// Шаг 2: childObj.__proto__.constructor === parentObj.constructor ===
// Шаг 3: childObj.__proto__.__proto__.constructor === parentObj.__proto__.constructor === ParentObj.prototype.constructor === ParentObj

// Почему же так не получается с childObject`ом?
// Почему его свойство "__proto__" не ссылается на объект, который
// содержит свойство "constructor", ссылающееся на его конструктор - СhildObject?
// Потому, что мы ему при наследовании прототип заменили на parentObj и теперь
alert('childObj.constructor === parentObj.prototype = ' + (
    childObj.constructor === parentObj.constructor
));//true

//В отличие от parentObj, которому прототип не подменяли (не наследовали) и по-этому у него по ссылке
// "__proto__" остался его родной, автоматически созданный объект, содержащий "правильную" ссылку
// "constructor":
alert('parentObj.__proto__.hasOwnProperty(\'constructor\') = ' + (
    parentObj.__proto__.hasOwnProperty('constructor')
));//true
alert('parentObj.__proto__.constructor === ParentObj = ' + (
    parentObj.__proto__.constructor === ParentObj
));//true - чего childObj`а мы лишили в угоду наследования.

/* Итак, проблема: мы не можем, имея только ссылку на объект, в отношении которого произведено наследование
   (данным способом), получить ссылку на его конструктор.
   
   Теоретическая база: при создании объекта функции автоматически создаётся ещё один объект, которому
   назначается свойство "constructor", ссылающееся на этот самый объект функции, а функция ссылается на него
   через свойство "prototype". При создании объекта с помощью этого конструктора происходит присваивание
   obj.__proto__ = Obj.prototype, так что объект может найти свой конструктор по ссылке
   obj.__proto__.constructor. ScriptEngine при вызове свойства объекта в случае, если его не находит,
   совершает восхождение по ссылкам "__proto__" этого объекта, пока не найдёт нужное свойство, либо не упрётся
   в null (Object.prototype.__proto__ == null) - тогда возбуждается исключение.
   Всё хорошо работает до тех пор, пока мы не решаем использовать этот механизм для наследования. При
   наследовании мы ещё до создания экземпляра объекта присваеваем свойству "prototype" конструктора объекта
   ссылку на объект родителя. Этот объект замещает тот объект, который был автоматически создан при создании
   объекта функции, но, в отличие от него, не содержит обратной ссылки на конструктор - т.е. на этот объект
   функции. В итоге ссылка на конструктор теряется...
   
   В случае с тремя шагами наследования мы получим для внука конструктор дедушки, четырёх - прадедушки и т.д.
*/

// ******************* Часть вторая: "Попытка решить проблему влоб"
// в которой у родителя отбирают его конструктор и вручают конструктор его ребёнка вместо его конструктора

// Что же можно сделать?
// Напрашивается следующее: раз мы при наследовании подставляем свойству "prototype" конструктора новое
// значение, не имеющее ссылки "constructor", взамен старого, имевшего это свойство, то почему бы нам не
// присвоить этому объекту это свойство принудительно, что бы изначальное соглашение продолжало выполняться?

// Давайте так и сделаем:
parentObj.constructor = ChildObj;
// мы это можем сделать сразу же, следующим шагом после реализации наследования, когда у нас ссылка
// на ChildObj ещё под носом. Можем даже, воспользовавшись тем, что любое присваивание возвращает
// присваиваемый результат, сделать такое заплаточное наследование одним действием:
// (СhildObj.prototype = parentObj = new ParentObj()).constructor = ChildObj;

//Вуаля! Мы решили проблему:
alert('childObj.constructor === ChildObj = ' + (
    childObj.constructor === ChildObj
)); // теперь - true - Победа!

// После того, как побегали, попрыгали, покидали шапки в воздух и натанцевались вдоволь,
// давайте подумаем - какой ценой нам эта победа досталась?
// Очень даже большой! Теперь мы нарушили соглашение для значения ссылки "prototype" у объекта ParentObj:
alert('parentObj.constructor === ParentObj = ' + (
    parentObj.constructor === ParentObj
));//false... Что же мы наделали? Т.е. теперь ребёнок нашёл, а родитель - потерял свой конструктор!

// А куда же теперь ссылается конструктор родителя?
alert('parentObj.constructor === ChildObj = ' + (
    parentObj.constructor === ChildObj
));//true - вот куда он ссылается - на конструктор своего ребёнка. Почему?

// Просто раньше у нашего объекта parentObj отсутствовало свойство "constructor" и когда мы его вызывали,
// в отсутсвии этого свойства у него вызывалось свойство "__proto__" и у него уже вызывалось свойство
// "constructor". Это выражение на самом деле верно по-прежнему:
alert('parentObj.__proto__.constructor === ParentObj = ' + (
    parentObj.__proto__.constructor === ParentObj
));//true

// Но теперь нарушилась неявная цепочка вызова, ведь больше не выполняется равенство
alert('parentObj.constructor === parentObj.__proto__.constructor = ' + (
    parentObj.constructor === parentObj.__proto__.constructor
));//false - а раньше, до нашего этого решения, оно выполнялось и - всё с parentObj было в порядке!

// Т.е. решение не годится, если мы конечно, признаём, что каждый объект в цепочке наследования должен иметь
// возможность получить ссылку на свой конструктор.


// *************** Часть третья: "Настоящее решение проблемы"
// в которой все счастливы

// Итак, присваивать ссылку на конструктор прототипу объекта в условиях наследования нельзя, а на объект
// функции как-то ссылаться надо, но не так, как мы сделали до этого.

/* Как же? Давайте подумаем.
   
   Вот в прошлой части мы присвоили parentObj прямую ссылку на конструктор и в итоге закрыли свойство
   "__proto__.constructor", которое вызывалось до этого и вело куда нужно - к объекту-функции ParentObj,
   являющемуся конструктором объекта parentObj. Так может, было бы лучше ему и всем остальным объектам
   ссылаться напрямую на свои конструкторы?
   
   Это было бы решением: каждый объект ссылался бы на свой конструктор напрямую, а не посредством
   неявной ссылки и мы таким образом не теряли бы ссылок на конструкторы:
*/
childObj.constructor = ChildObj;
parentObj.constructor = ParentObj;

/* Но такой вариант будет не удобен для конечного пользователя библиотеки. Ведь мы помним, что данная
   проблема для нас получает актуальность лишь когда мы создаём большие приложения с длинными цепочками
   наследования. В таких приложениях программист, который использует доставшуюся ему библиотеку, не
   должен задумываться над тем, что бы применять хитрые приёмы для создания объектов. Мы же обязываем
   его делать примерно следующее:
*/
var child2Obj = new ChildObj;
child2Obj.constructor = ChildObj;

//Или
var child3Obj;
(child3Obj = new ChildObj()).constructor = ChildObj;

// Трудно ожидать такого от неизвестного пользователя. Так что нужно как-то выкручиваться при создании
// самой библиотеки.

// Напрашивается простая и бессмысленная с математической точки зрения, однако имеющая смысл в
// программировании вставка такого выражения в функцию-конструктор: "this.constructor = this.constructor;".
var ChildObj2 = function(){
    
    alert('this.constructor = ' + (
        this.constructor = this.constructor
    ));
} //так мы вытаскиваем конструктор из свойства this.__proto__ и присваиваем его получающемуся объекту

//Наследуем
ChildObj2.prototype = new ParentObj;

//Но не тут-то было:
var childObj2 = new ChildObj2;//"this.constructor = function(){}" - это не конструктор ChildObj2.

// На самом деле это - конструктор ParentObj:
alert('childObj2.constructor === ParentObj = ' + (
    childObj2.constructor === ParentObj
));//true

// Выходит, что даже на этапе конструирования мы не можем сослаться на тот метод, который в данный момент
// выполняется - т.е. на конструктор. Это объясняется тем, что присваивание
// childObj2.__proto__ = ChildObj2.prototype
// происходит до того, как запускается конструктор, а не после. По-этому придётся вписать имя конструктора:
var ChildObj3 = function(){
    
    alert('this.constructor = ChildObj3 = ' + (
        this.constructor = ChildObj3
    ));
}

//Наследуем
ChildObj3.prototype = new ParentObj;

//Создаём экземпляр
var childObj3 = new ChildObj3;


//В общем, счастье есть. На последок проверим, всё ли в порядке:
alert('childObj3 instanceof ChildObj3 = ' + (
    childObj3 instanceof ChildObj3
));//true

alert('childObj3 instanceof ParentObj = ' + (
    childObj3 instanceof ParentObj
));//true



--------------------
  )
 (
[_])
проф. блог

Кролики думали, что занимаются любовью, а на самом деле их просто разводили...
PM MAIL WWW Skype GTalk   Вверх
AKS
Дата 4.6.2008, 17:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Участник форума
**


Профиль
Группа: Участник
Сообщений: 725
Регистрация: 20.9.2006

Репутация: 27
Всего: 52



Это все ради того, чтобы получить возможность написать что-то, вроде:
Код

childObj3.constructor.prototype.constructor.prototype...

? Или есть еще мотивы?
PM MAIL   Вверх
Се ля ви
Дата 4.6.2008, 22:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Java/SOAрхитектор
****


Профиль
Группа: Модератор
Сообщений: 2016
Регистрация: 5.6.2004
Где: place without tim e and space

Репутация: 5
Всего: 127



AKS, я писал:
Цитата(Се ля ви @  3.6.2008,  15:46 Найти цитируемый пост)
Думается, что использование длинных деревьев наследования обязательно спотыкнётся об это обстоятельство или по крайней мере создаст большие неудобства.


Просто не знаю - элементарно дискомфортно иметь объект, но не иметь при этом ссылки на его конструктор.

Как-то так... smile


--------------------
  )
 (
[_])
проф. блог

Кролики думали, что занимаются любовью, а на самом деле их просто разводили...
PM MAIL WWW Skype GTalk   Вверх
AKS
Дата 5.6.2008, 11:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Участник форума
**


Профиль
Группа: Участник
Сообщений: 725
Регистрация: 20.9.2006

Репутация: 27
Всего: 52



Цитата(Се ля ви @  4.6.2008,  22:09 Найти цитируемый пост)
...использование длинных деревьев наследования обязательно спотыкнётся об это обстоятельство или по крайней мере создаст большие неудобства.

Ключевая фраза: "использование длинных деревьев... создаст большие неудобства". И это совершенно верно!
На самом деле, мне просто жаль (честное слово ;) ) вашего времени, сил и энергии, которые могут быть напрасно истрачены. А ведь можно изменить подход и начать думать по-js’овски.
Вот, специально для этого случая нашел кое-какие высказывания js-гуру (как раз есть кое-что по-поводу "длинных деревьев наследования" и прочей class-based мишуры):
Цитата

Douglas Crockford:
JavaScript's prototypal inheritance has more expressive power than classical inheritance

JavaScript can be used like a classical language, but it also has a level of expressiveness which is quite unique. 

Classical objects are hard. The only way to add a new member to a hard object is to create a new class. In JavaScript, objects are soft. A new member can be added to a soft object by simple assignment.
Because objects in JavaScript are so flexible, you will want to think differently about class hierarchies. Deep hierarchies are inappropriate. Shallow hierarchies are efficient and expressive.


Richard Cornford:
In a class-based language a class is defined in the source code and is absolutely fixed while the code is executing. In javascript all objects are mutable. Any property can be added to any object at any time and prototypes can be extended, replaced, swapped and so on…

This run-time flexibility is a strength of javascript and it should not be denied or avoided out of a dogmatic belief that a class-based approach is intrinsically superior.

Я подчеркнул на мой взгляд наиболее значимые моменты (если будут трудности с переводом. то могу помочь ;) ). Надеюсь, что эти высказывания опытных программистов как-нибудь когда-нибудь пригодятся...
Happy scripting (как пишут англоязычные программисты)! smile
PM MAIL   Вверх
Се ля ви
Дата 5.6.2008, 12:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Java/SOAрхитектор
****


Профиль
Группа: Модератор
Сообщений: 2016
Регистрация: 5.6.2004
Где: place without tim e and space

Репутация: 5
Всего: 127



AKS, большое спасибо, что нашли эти высказывания!

Это уже превращается в философскую дискуссию. Что бы было понятно по аналогии, приведу свою заметку в ЖЖ двухлетней давности:
Цитата(http://se-la-vy.livejournal.com/9375.html)
Когда я был подростком, мне очень нравилось кататься на скейте. Занимаясь этим, я обратил внимание, что стандартная товарная настройка скейта даёт очень жесткую езду, скейт обладает низкой манёвренностью и порой трудно вписаться в резкий поворот, только легко едешь прямо и плавно поворачиваешь.
Поняв это, я взялся его подкручивать. После этого я уже действительно мог на нём делать всё, что хотел. Не раз возвращался домой со ссадинами и, подкрашенный зелёнкой или йодом, снова рвался кататься.
Но ценой такой манёвренности стало то, что скейт практически потерял устойчивость и просто ехать на нём стало практически невозможно, внимание было всецело приковано к тому, как я еду, даже если дорога была прямая – отвлёкся и уже въехал в бортик. Потом мне рассказали, что это основа характеристик любых технических систем, и конструкторы всегда ищут некоторый практичный баланс манёвренности и устойчивости – и в истребителях и в машинах – во всём.


Или другие мои рассуждения, касающиеся вопроса о свободе:
Дождевой кольчатый червяк не имеет скелета и может изгибаться как ему заблагорассудится, как не может изгибаться ни один гимнаст. Более того, он обладает настолько простой структурой тела, что легко восстанавливается, если его разорвать - и будет два червяка.
Но человек за счёт скелета и сложности строения организма, имеет прямохождение, которое если и может добиться червяк, встав на свои кончики, то оно дастся ему страшно большой потерей энергии и фактически недостижимо.
Т.е. свобода в одном означает отсутсвие свободы в другом.


В общем, все достоинства - они же и обратные стороны недостатков и тут нужен баланс в зависимости от того, чего хочется добиться.
В Java, которой я занимаюсь, тоже есть феноменальная гибкость, но там эти методы вынесены в отдельный пакет java.reflection которым не принято пользоваться без необходимости - что бы не наводить бардака в программе. С её помощью тоже можно добавлять, удалять и заменять методы объектов, создавать классы на лету и делать всё что угодно, нарушая каноны class-based программирования, но это используют обычно только при написании сред разработки, в остальных приложениях использование Reflection API считается дурным тоном и используется по минимуму.

И мощность и масштаб Java-приложений в итоге зашкаливает. А с другой стороны, не использование Reflection API подавляющим большинством программистов позволяет делать прекрасные средства разработки типа IntelliJ IDEA, которые очень сильно помогают при разработки больших приложений.

Я представляю, насколько тяжело было людям разрабатывать тот же GMail, если они, как вы выражаетесь, мыслили по-js`овски. Мне хочется найти способ проще создавать большие приложения и для этого необходим иной компромисс жёсткости и гибкости для этого языка - и мне кажется, что пример в этом как раз и можно брать с Java.

Вот я и пытаюсь выработать рекомендации по программированию на JS для того, что бы реализовать такой компромисс и сделать возможным создание хитрых web-интерфейсов и удобных средств для их разработки. smile


--------------------
  )
 (
[_])
проф. блог

Кролики думали, что занимаются любовью, а на самом деле их просто разводили...
PM MAIL WWW Skype GTalk   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Форум для вопросов, которые имеются в справочниках, но их поиск вызвал затруднения, или для разработчика требуется совет или просьба отыскать ошибку. Напоминаем: 1) чётко формулируйте вопрос, 2) приведите пример того, что уже сделано, 3) укажите явно, нужен работающий пример или подсказка о том, где найти информацию.
 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | JavaScript: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1248 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.