Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 19.01.2010, 18:09
Аватар для Shaci
:-/
Отправить личное сообщение для Shaci Посмотреть профиль Найти все сообщения от Shaci
 
Регистрация: 28.09.2009
Сообщений: 1,125

Вопрос про ООП, цепочки прототипов.
Попробовал разобраться в наследовании объектов по прототипам, тема сложная местами, поэтому возникают вопросы...(вопросы в комментах кода, ближе к концу). Код сочинял сам, возможно где-то сильно заблуждаюсь в комментах.

//первый "класс"
   //по умолчанию, прототипом объектов данного "класса" является
   //объект встроенного класса Object
   //Свойство MyArray1.prototype = new Object()
   var MyArray1 = function() {};
   //Создаем объект класса MyArray1
   var first = new MyArray1();//
   //MyArray1.prototype = объекту-прототипу (класса Object), который
   //по умолчанию имеет единственое свойство constructor,
   //В общем случае свойство constructor объекта указывает на его конструктор,
   //но в данном случае, constructor прототипа указывает на саму функцию конструктор,
   //с которой этот прототип ассоциируется, т.е. на MyArray1
   alert("First object");
   alert("constructor");
   alert("(MyArray1.prototype.constructor == MyArray1) = " + (MyArray1.prototype.constructor == MyArray1));//true

   alert("(MyArray1.prototype.constructor == Object)=" + (MyArray1.prototype.constructor == Object));//false
   //а это в общем случае:свойство конструктор будет указывать на конструктор данного объекта
   alert("(first.constructor == MyArray1) = " + (first.constructor == MyArray1));//true
   alert("(first.constructor == Object) = " + (first.constructor == Object));//false
   
   //создадим второй "класс"
   var MyArray2 = function() {};

   //оператор instanceof
   alert("instanceof");
   alert("(first instanceof MyArray1) = " + (first instanceof MyArray1));//true
   alert("(first instanceof MyArray2) = " + (first instanceof MyArray2));//false
   alert( "(first instanceof Object) = " + (first instanceof Object));//true

   //Далее назначим явно прототип   
   MyArray1.prototype = new MyArray2();
   //второй объект класса MyArray1(), теперь уже у класса другой прототип
   var second = new MyArray1();

   alert("Second object");
   //оператор instanceof
   alert("instanceof");
   alert("(second instanceof MyArray1) = " + (second instanceof MyArray1));//true
   alert("(second instanceof MyArray2) = " + (second instanceof MyArray2));//true
   alert( "(second instanceof Object) = " + (second instanceof Object));//true

   alert("constructor");
   //Так как теперь прототип указан "явно", то, по умолчанию, его свойство constructor равно его
   //коструктору
   alert("(MyArray1.prototype.constructor == MyArray2) = " + (MyArray1.prototype.constructor == MyArray2));//true
   //и, соответственно
   alert("(MyArray1.prototype.constructor == MyArray1) = " + (MyArray1.prototype.constructor == MyArray1));//false
   //теперь наследование свойства constructor, происходит , видимо, несколько не так, как
   //наследование обычного свойства:
   alert("(second.constructor == MyArray1) = " + (second.constructor == MyArray1));//false
   alert("(second.constructor == MyArray2) = " + (second.constructor == MyArray2));//true - наследуется свойство constructor прототипа
   //хотя по идее, если не ошибаюсь, должно происходить перекрытие свойств родителя

   //----------------------------------------------------------------------
   //До этого момента логика была более менее связная...
   
   //Вот теперь вопрос
   //Если мы "продолжим" наследование
   MyArray2.prototype = new Array();

   //т.е. по идее: объекты "класса" MyArray1 имеют прототипом объект класса MyArray2
   //а объекты класса MyArray2 - прототипом объект класса Array()
   //=> вроде как цепочка
   var third = new MyArray1();

   alert("Third object");
   //Совбственно дальше один большой вопрос, почему alert выдает такие значения?
   alert("instanceof");
   alert("(third instanceof MyArray1) = " + (third instanceof MyArray1));//true
   alert("(third instanceof MyArray2) = " + (third instanceof MyArray2));//false ?????????????????
   alert("(third instanceof Array) = " + (third instanceof Array));//false ?????????????????
   alert("(third instanceof Object) = " + (third instanceof Object));//true

   alert("constructor");
   alert("(MyArray1.prototype.constructor == MyArray2) = " + (MyArray1.prototype.constructor == MyArray2));// ??? true, а здесь не
   //должно происходить какое-нибудь очередное наследование конструктора прототипа?,
   //он же объект класса MyArray2 и имеет прототип - объект класса Array => его конструктор
   //по идее должен наследоваться?
   //т.е. MyArray1.prototype.constructor по идее должен быть равен Array???? или нет..
   alert("(MyArray1.prototype.constructor == Array) = " + (MyArray1.prototype.constructor == Array));//false ???
   alert("(MyArray1.prototype.constructor == MyArray1) = " + (MyArray1.prototype.constructor == MyArray1));//false
   
   alert("(third.constructor == MyArray1) = " + (third.constructor == MyArray1));//false
   alert("(third.constructor == MyArray2) = " + (third.constructor == MyArray2));//true
   alert("(third.constructor == Array) = " + (third.constructor == Array));//false , здесь не происходит дальнейшего наследования????
Ответить с цитированием
  #2 (permalink)  
Старый 20.01.2010, 14:38
Профессор
Отправить личное сообщение для Dmitry A. Soshnikov Посмотреть профиль Найти все сообщения от Dmitry A. Soshnikov
 
Регистрация: 25.02.2008
Сообщений: 707

Сообщение от Shaci
//Далее назначим явно прототип
MyArray1.prototype = new MyArray2();
MyArray1.prototype - теперь "пустой" объект (порождённый от MyArray2), не имеющий свойства constructor.

Сообщение от Shaci
//Так как теперь прототип указан "явно", то, по умолчанию, его свойство constructor равно его
   //коструктору
   alert("(MyArray1.prototype.constructor == MyArray2) = " + (MyArray1.prototype.constructor == MyArray2));//true
   //и, соответственно
   alert("(MyArray1.prototype.constructor == MyArray1) = " + (MyArray1.prototype.constructor == MyArray1));//false
У MyArray1.prototype, собственного свойства constructor, как мы отметили выше, нет, так? Соответственно, оно откуда-то наследуется (раз равенство на MyArray2 даёт true).

В общем случае схема очень простая:

1. При обращении к свойству объекта, если оно не найдено в самом объекте, его поиск продолжается в прототипе объекта; далее, если не найдено, в прототипе прототипа и т.д. - т.е. в цепи прототипов;

2. Самый важный момент - прототип объекта - это внутреннее (недоступное напрямую) свойство [[Prototype]]. Свойство же .prototype из конструктора объекта - это ссылка на прототип, из которой будет установлен [[Prototype]] объекта при создании объекта. Сам же объект (после того, как был создан) держит связь со своим прототипом через это свойство [[Prototype]].

Поэтому цепь прототипов - это:

object.[[Prototype]].[[Prototype]].[[Prototype]].и т.д., пока не будет null


Возвращаясь к MyArray1.prototype,

MyArray1.prototype порождён от конструктора MyArray2 и является обычным объектом; прототип MyArray1.prototype установлен из MyArray2.prototype:

MyArray1.prototype.[[Prototype]] === MyArray2.prototype


Соответственно, при обращении к MyArray1.prototype.constructor, свойство constructor будет найдено по цепи:
MyArray1.prototype.constructor --> не найдено;
MyArray1.prototype.[[Prototype]].constructor --> найдено и == MyArray2


Равенство MyArray1.prototype.constructor == MyArray1 будет давать, правильно, false, опять же, из-за особенности цепи прототипов. Чтобы исправить это, свойство constructor, после смены свойства .prototype в конструкторе, выставляют вручную:

MyArray1.prototype = new MyArray2();
MyArray1.prototype.constructor = MyArray1;


Сообщение от Shaci
//теперь наследование свойства constructor, происходит , видимо, несколько не так, как
   //наследование обычного свойства:
   alert("(second.constructor == MyArray1) = " + (second.constructor == MyArray1));//false
   alert("(second.constructor == MyArray2) = " + (second.constructor == MyArray2));//true - наследуется свойство constructor прототипа
   //хотя по идее, если не ошибаюсь, должно происходить перекрытие свойств родителя
После смены свойства constructor вручную, должно быть правильно:

second.constructor == MyArray1; // true
second.constructor == MyArray2; // false


Опять же, свойство constructor в объекте second найдено по цепи:

second.constructor --> нет
second.[[Prototype]].constructor --> (мы выставили его вручную) да === MyArray1

Если бы не выставили, было бы:

second.constructor --> нет
second.[[Prototype]].constructor --> нет
second.[[Prototype]].[[Prototype]].constructor --> да === MyArray2


Подробней про прототип: http://javascript.ru/blog/Dmitry-A.-...-OOP.#prototip

Сообщение от Shaci
alert("(MyArray1.prototype.constructor == MyArray2) = " + (MyArray1.prototype.constructor == MyArray2));// ??? true, а здесь не
   //должно происходить какое-нибудь очередное наследование конструктора прототипа?,
   //он же объект класса MyArray2 и имеет прототип - объект класса Array => его конструктор
   //по идее должен наследоваться?
   //т.е. MyArray1.prototype.constructor по идее должен быть равен Array???? или нет..
Как уже было сказано, прототип объекта (внутреннее свойство [[Prototype]]) устанавливается при создании объекта и дальше изменён (полностью на новый объект) быть не может. Поэтому MyArray1.prototype.[[Prototype]] установился в MyArray2.prototype при создании через new MyArray2().

Прочитайте статью про ООП полностью: http://javascript.ru/blog/Dmitry-A.-...-CHast-7.-OOP.

Успехов!
__________________
Тонкости ECMAScript

Последний раз редактировалось Dmitry A. Soshnikov, 20.01.2010 в 14:45.
Ответить с цитированием
  #3 (permalink)  
Старый 21.01.2010, 13:11
Аватар для Shaci
:-/
Отправить личное сообщение для Shaci Посмотреть профиль Найти все сообщения от Shaci
 
Регистрация: 28.09.2009
Сообщений: 1,125

Спасибо, статьи как раз для понимания стоящие, и, надеюсь, позволят не читать спецификацию)),
попробую разобраться, буду задавать вопросы.
Ответить с цитированием
  #4 (permalink)  
Старый 26.01.2010, 16:26
Аватар для Shaci
:-/
Отправить личное сообщение для Shaci Посмотреть профиль Найти все сообщения от Shaci
 
Регистрация: 28.09.2009
Сообщений: 1,125

Позволю себе немного пофлудить,
в механизме наследования вроде разобрался:
вот пара примерчиков

//Пример, вариант 1:
function A() {};
function B() {};
function C() {};

B.prototype = new C();
alert(B.prototype.__proto__.constructor == C);//true
//B.prototype.__proto__.constructor (да) --> C
alert(B.prototype.__proto__.__proto__.constructor == Object);//true
//у класса C, C.prototype = new Object()(но с определенным свойством constructor, т.е. {constructor:C;},
//C.prototype.__proto__ = Object.prototype
//C.prototype.constructor = (установлено явно и автоматически при создании) C, C.prototype.__proto__.constructor = Object
//т.е. у "Пустого" прототипа явно устанавливается свойство constructor = C,
//иначе происходило бы наследование этого свойства от прототипа прототипа,
//у прототипа прототипа - так же явно - свойство конструктора Object

alert(B.prototype.constructor == C);//true
//B.prototype.constructor (нет) -->
//B.prototype.__proto__.constructor (да) --> C

alert((new B()).constructor == C);//true
//(new B()).constructor (нет) -->
//B.prototype.constructor (нет) -->
//B.prototype.__proto__.constructor (да) --> C

//Далее
A.prototype = new B();
alert(A.prototype.constructor == C);//true
//A.prototype.constructor (нет) -->
//B.prototype.constructor (нет) -->
//B.prototype.__proto__.constructor (да) --> C
//и.т.д
alert((new A()).constructor == C);//true
//A.constructor --> (нет)
//A.prototype.constructor (нет) -->
//B.prototype.constructor (нет) -->
//B.prototype.__proto__.constructor (да) --> C

//B.prototype.__proto__.constructor = C.prototype.constructor, это понятно


//А вот здесь возникал вопрос, но вроде я на него правильно ответил
//Вариант 2:
function A() {};
function B() {};
function C() {};
var xxx = new B();
A.prototype = xxx;
alert(A.prototype.constructor == B.prototype.constructor);//true, здесь все понятно
alert((new A()).constructor == B.prototype.constructor)//true, ну и далее, сколько угодно вариаций

B.prototype = new C();
alert(C.prototype.constructor == C);//true - понятно
alert(B.prototype.constructor == C);//true - понятно,
alert((new B).constructor == C);//true - понятно

//Вопрос вот здесь возникал:
alert(A.prototype.constructor == C);//false ??????????????????, разве не должен быть true?, ведь мы вроде поменяли свойство constructor у объекта класса B
alert(A.prototype.constructor == B);//true :( !!!
//получается, что прототипом класса A является объектб  который уже существует со своими определенными
//свойствами, и дальнейшие изменения функции конструктора его не касаются, вроде так?
alert(xxx.__proto__.constructor == B);//true!!!!!!
//a не alert(xxx.__proto__.constructor == C); //true
//Т.е. у этого объекта остается старый прототип!!!
//=> у всех объектов класса A будет старый прототип
/*
Из статьи:
Однако, изменение свойства .prototype в конструкторе,
никак не влияет на прототип уже порождённых объектов.
Меняется только (и именно) свойство .prototype конструктора.
Это означает, что новые порождаемые объекты, будут иметь новый прототип.
Порождённые же уже (до смены свойства .prototype) объекты,
имеют связь со своим старым прототипом, и эта связь уже неизменна:
 */



Собственно, похоже, что наткнулся как раз на 2 этих "подводных камня":
из http://javascript.ru/blog/Dmitry-A.-...-OOP.#prototip
1.
Часто в данном моменте бывает путаница - свойство .constructor неверно считают родным свойством порождённого объекта; как видим (в алгоритме создания функций), данное свойство является свойством прототипа, и доступно объекту посредством делегирования.

И
2.
С прототипом объекта также иногда бывает путаница - в качестве него могут неверно считать явную ссылку конструктора - .prototype. Да, действительно, эта ссылка указывает на тот же объект, что и свойство [[Prototype]] объекта:
a.[[Prototype]] ----> Прототип <---- A.prototype

Более того, как мы видели в алгоритме создания объектов, [[Prototype]] черпает информацию из .prototype. Однако, изменение свойства .prototype в конструкторе, никак не влияет на прототип уже порождённых объектов. Меняется только (и именно) свойство .prototype конструктора. Это означает, что новые порождаемые объекты, будут иметь новый прототип. Порождённые же уже (до смены свойства .prototype) объекты, имеют связь со своим старым прототипом, и эта связь уже неизменна

Вроде так.
Ответить с цитированием
  #5 (permalink)  
Старый 26.01.2010, 19:10
Профессор
Отправить личное сообщение для Dmitry A. Soshnikov Посмотреть профиль Найти все сообщения от Dmitry A. Soshnikov
 
Регистрация: 25.02.2008
Сообщений: 707

Сообщение от Shaci
Вроде так.
Именно так
__________________
Тонкости ECMAScript
Ответить с цитированием
  #6 (permalink)  
Старый 27.01.2010, 14:50
Аватар для Shaci
:-/
Отправить личное сообщение для Shaci Посмотреть профиль Найти все сообщения от Shaci
 
Регистрация: 28.09.2009
Сообщений: 1,125

Хе хе)), неужто мне открылись тайны ООП в javascript),
теперь осталось разобраться с instanceof, там вроде немного
И потом можно читать весь цикл статей).
Ответить с цитированием
Ответ



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

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


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Вопрос: И опять про offsetLeft... sigurd Общие вопросы Javascript 11 04.10.2010 14:06
вопрос про <select> Krondor Общие вопросы Javascript 2 25.11.2009 17:04
Вопрос про $ в jquery vvsh Общие вопросы Javascript 6 06.09.2009 18:50
Вопрос про отправку данных методом Post QQQ AJAX и COMET 1 15.07.2009 23:27
Вопрос про вызов события onClick skyfish Общие вопросы Javascript 12 27.12.2008 19:12