Вопрос про ООП, цепочки прототипов.
Попробовал разобраться в наследовании объектов по прототипам, тема сложная местами, поэтому возникают вопросы...(вопросы в комментах кода, ближе к концу). Код сочинял сам, возможно где-то сильно заблуждаюсь в комментах.
//первый "класс" //по умолчанию, прототипом объектов данного "класса" является //объект встроенного класса 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 , здесь не происходит дальнейшего наследования???? |
Цитата:
Цитата:
В общем случае схема очень простая: 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; Цитата:
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 Цитата:
Прочитайте статью про ООП полностью: http://javascript.ru/blog/Dmitry-A.-...-CHast-7.-OOP. Успехов! |
Спасибо, статьи как раз для понимания стоящие, и, надеюсь, позволят не читать спецификацию)),
попробую разобраться, буду задавать вопросы. |
Позволю себе немного пофлудить,
в механизме наследования вроде разобрался: вот пара примерчиков //Пример, вариант 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) объекты, имеют связь со своим старым прототипом, и эта связь уже неизменна Вроде так. |
Цитата:
|
Хе хе)), неужто мне открылись тайны ООП в javascript), :)
теперь осталось разобраться с instanceof, там вроде немного И потом можно читать весь цикл статей). |
Часовой пояс GMT +3, время: 17:07. |