|
Понимание ООП в JavaScript
Чей-то почитал тут и там статьи и разное и запутался совсем . Что же такое ООП в JavaScript ...
Хотелось бы в этой теме провентилировать разные конкретные вопросы. Первый вопрос , чтобы зацепиться, такой : Если Array является объектом (встроенным) со свойствами constructor,length,prototype,concat,join etc..., то почему же я получаю эти свойства у его прототипа, а не у него самого : alert(Array.prototype.hasOwnProperty("join") ) // true alert(Array.hasOwnProperty("join")) // false? Тем более, что сказано в документации : Этот метод не проверяет наличие свойства по цепочке прототипов; указанным свойством должен обладать именно сам объект. А пример выше показывает, что именно сам объект Array не обладает свойством, а обладает, наоборот, - прототип Array.prototype . Короче , путаница получается - распутайте, плз. Кстати, и в этом контексте также непонятно, почему : var a = new Array(); alert(a.hasOwnProperty("join")) // false PS Вот еще непонятные в связи с этим вопросом вещи : var a = new Array(1,2); alert(a.join(";")+"= a.join(';') Работает"); alert(a.hasOwnProperty("join")+"=a.hasOwnProperty('join') У собств НЕТ") // false alert(Array.hasOwnProperty("join")+"=Array.hasOwnProperty('join') У Array НЕТ") // false alert(Array.prototype.hasOwnProperty("join")+"=Array.prototype.hasOwnProperty('join') У Array.prototype ЕСТЬ") // true alert(Array.prototype.isPrototypeOf(a)+"=Array.prototype.isPrototypeOf(a)"); // true alert(Array.isPrototypeOf(a)+"=Array.isPrototypeOf(a)"); // false alert() alert(Array.prototype.isPrototypeOf(Array)+"=Array.prototype.isPrototypeOf(Array)"); // false alert(Array.isPrototypeOf(Array)+"=Array.isPrototypeOf(Array)"); // true alert() alert(Object.prototype.isPrototypeOf(Array)+"=Object.prototype.isPrototypeOf(Array)"); // true alert(Object.isPrototypeOf(Array)+"=Object.isPrototypeOf(Array)"); // false alert() alert(Object.prototype.hasOwnProperty("constructor")+"=Object.prototype.hasOwnProperty('constructor')") // true alert(Function.hasOwnProperty("constructor")+"=Function.hasOwnProperty('constructor')") // false PPS. Может вообще кто-нибудь человеческим неформальным языком объяснить, что такое прототип, экземпляр объекта(или класса, не знаю , как правильно), объект(класс, не знаю , как в javascript надо говорить) ? |
на всякий случай.читали вы это?особенно вторую статью.
там по моему вполне качественно объясняется. если читали,и не поняли суть, то я даже не знаю как вам объяснить по другому |
Цитата:
|
дда хрен его знает, откровенно говоря.
не настолько я глубоко это знаю, как оказывается. как говорится воспринимайте образами и звуками. вот примерно так я и воспиринимаю.пожтому словами объяснить определения человеческим языком не могу. советую еще почитать оригинальную документацию, можеть она прояснит ва ситуацию. замечу что ваши тесты немного по разному работают в разных браузерах(вы тестировали, подозреваю в опере.в мозиле некоторые рузльтаты отличаются), и связано это с разной реализацией базовых типов.вот со своими объектами, думаю все будет одинаково в обоих браузерах |
Цитата:
|
Цитата:
Цитата:
|
Или вот такой совсем простой вопрос - что заносится, если заносится вообще, в свойство нового объекта prototype при его создании (т.е. (New {}).prototype чему равно и какого типа ) ?
|
kefi,
Прототип может быть только у конструктора (функции). Прототип это ссылка на объект, в котором будет производится поиск свойств, если они не были найдены в объекте, сформированным конструктором. С помощью прототипов в JavaScript реализуется наследование. Возможно вам что-то разъяснит следующий код: // Объявляем конструктор var constr = function() { // Объявляем свойство объекта this.a = 1; } // Объявляем свойство прототипа constr.prototype.b = 2; // Создаем объект конструктора var obj = new constr(); alert([obj.hasOwnProperty("a"), obj.a]); // true, 1 alert([obj.hasOwnProperty("b"), obj.b]); // false, 2 Свойства b в "собственных" свойствах объекта не было, но он был найден в прототипе. Вообще, рекомендую почитать статью о наследовании, я уверен, она ответит на ваши вопросы, касательно прототипов. |
|
2 Zeroglif > спасибо за ссылки, прочту, пока с пустой головой так быстро я не погружусь.
А пока : Цитата:
|
kefi,
Кто не наследуется? Конструктор? Или объект, созданный конструктором? Только это тут не причем (и функция и объект, естественно, связаны цепочкой прототипов), мы говорим о том, что свойство prototype есть только у конструкторов (хотя в mozilla есть свойство __proto__ у объектов). Связь объект-прототип происходит в момент создания объекта. Т.е. когда вы вызываете new конструктор;. Поскольку прототип это ссылка на объект, то вполне естественно, что все объекты, созданные конструктором, будут соединены с Object.prototype. |
Цитата:
|
есть объекты.
а есть функции-конструкторы. вот у функций-конструкторов(которые являются сами объектами, типа Function) есть свойство ptototype.оно есть только у функций, и влияет на создаваемые этими функциями-конструкторами объекты у обычных же объектов нету свойтва prototype есь внутренне своство(назовем его [[prototype]] к примеру), котороее ссылается на свойство prototype функции-конструктора, чоздавшей этот объект.если у объекта нету какого-то свойства, то оно ищется в объекте [[prototype]]. свойство [[prototype]] нигде не доступнов явном виде, и работать с ним напрямую невозможно(исключение:в мозилле оно доступно под именем __proto__), поэтому его имя для нас не так важно. таким образом свойство prototype(не путать с [[prototype]])есть только у функций-конструкторов(любая функция может быть функцией-конструкотором, если внетри нее используются конструкция this) Object - это функция конструктор тоже.она создает объект типа Object Любая функция должна иметь prototype ссылающийся на объект по умолчанию это экземпляр типа Object но, можно заменить на любой другой свой объект.именно на объект,а не на функцию-конструктор. свойство prototype функции-конструктора указывает какой объект должен быть в свойстве [[prototype]] создаваемого объекта.именно это [[prototype]] и называется прототипом объекта. таким образом у всех объектов создаваемых одной функцией-конструктором прототип будет общий. в свою очередь у этого прототипа есть свой прототип.в вершине этого дерева находится объект типа Object вот так вот сумбурно попытался объяснить суть дела если не прав, кто-нибудь исправьте PS еще раз:свойство prototype функции-конструктора не является прототипом функции.но оно указывает какой объект будет прототипом создаваемых объектов |
Цитата:
var a = function() {} a.prototype.hi = 1; alert(a.__proto__ == a.prototype); // false Цитата:
Вообще, в спецификации есть довольно неплохие определения конструктора и прототипа: Цитата:
Цитата:
|
Андрей Параничев,
я опечатался. вернее не полностью напечатал фразу уже исправил |
Цитата:
kefi, Ещё раз детальней постарайтесь прочитать материал по первой ссылке, которую Вам дал Zeroglif (там он достаточно хорошо и доступно объяснил). Если останутся вопросы (а они, конечно же, могут остаться, если Вы только начинаете изучать JS), то можно их уже будет локализовать и определить моменты, где именно остались неясности. |
Цитата:
var constr = function(){ this.a = 1;} //var constr = new Function("this.a = 1;") // <- или так //alert([constr.__proto__ == constr.prototype,constr.__proto__ == constr.constructor.prototype]); // false , true alert([constr.prototype == constr.constructor.prototype, constr.prototype, constr.constructor.prototype]); // false,[object Object], function prototype() { [native code] } Т.е. прототипом вновь создаваемых объектов подобных constr , будет constr.constructor.prototype==function prototype() { [native code] } , а прототипом функции function(){ this.a = 1;} будет constr.prototype== [object Object] . ? |
Цитата:
alert(constr.__proto__); // оригинальный Function.prototype, который равен function () {} alert(constr.constructor.prototype); // то же самое, т.к. конструктор у constr - Function alert(constr.constructor.prototype === constr.__proto__); Однако, т.к. constr сам конструктор, то все порождённые от него объекты также будут иметь свой __proto__: var a = new constr(); alert(a.__proto__); // объект, на который так же указывает constr.prototype (пока эта ссылка есть) alert(a.__proto__ === constr.prototype); // действительно, они указывают на один объект Поэтому родной прототип конструктора constr - это constr.__proto__, а прототип порождаемых от constr объектов - constr.prototype (порождённые объекты от constr будут смотреть на constr.prototype через .__proto__. Причём, ссылка constr.prototype может исчезнуть позже, а порождённыйОбъект.__proto__ - нет). |
прототипом вновь создаваемых объектов типа constr,т.е. создаваемых при помощи
obj=new constr() будет obj.__proto__==constr.prototype==obj.constructor.prototype то есть объект [object Object] прототипом же функции constr , создаваемой var constr = function(){ this.a = 1;}//так var constr = new Function("this.a = 1;") // <- или так будет constr.__proto__==Function.prototype==constr.constructor.prototype то есть function(){} PS малясь не успел,но дуаю будет полезно |
2 Gvozd> Ну да, я Вас понял буквально и неверно , - что прототип объекта - это объект.prototype,
Т.е. ВСЕГДА нужно понимать так, что прототип объекта - это прототип его конструктора, т.е. объект.constructor.prototype, |
блин, да нет же.
интересно где я не так начал объяснять. __proto__(или же [[prototype]], что есть одно и тоже) и prototype - это разные вещи. __proto__(или же [[prototype]]) это и есть прототип объекта. если у объекта не находится какое-то свойство, то оно начинает искатся в его прототипе.затем в прототипе прототипа.и так пока не дойдет до самого верхнего прототипа - объекта [object Object] prototype - это такое свойство у функции-конструктора, которое определяет какой прототип будет у объектов создаваемых этим конструктором.НО, это НЕ ПРОТОТИП самой функции. Прототипом самой функции является пустая функция function(){} ТО ЕСТЬ ЭТО НЕВЕРНО: Цитата:
Цитата:
Цитата:
Цитата:
//constr- функция-конструктор.все что будет объявлено посредством (new constr()) будет иметь тип constr var constr = function() {this.a = 1;} //var constr = new Function("this.a = 1;") // <- или так //Function - функция-конструктор для всех прочих функций alert(constr.__proto__==Function.prototype);//TRUE //прототипом функции constr(а она помимо всего прочего также является объектом) является объект, заданный в свойстве prototype ее конструктора alert(constr.__proto__);//function(){} //прототипом функции constr является просто пустая функция. //у всех функций один общий прототип.этот прототип является объектом-пустой функцией //------------------------------------------------------------------------------------------------ //вот мы задаем, что у всех объектов, созданных при помощи new constr() будет общий прототип. //прототип функции от это не меняется constr.prototype={'b':2} //а вот мы создаем объект при помощи нашего конструктора obj=new constr() alert(obj.__proto__==constr.prototype);//TRUE //прототипом объекта, созданного при помощи конструктора constr является объект, заданный в свойстве prototype его конструктора alert(obj.__proto__);// этот объект: {'b':2} alert('obj.a='+obj.a)//1 .свойство берется из самого объекта alert('obj.b='+obj.b)//2 .свойство берется из прототипа объекта obj2=new constr()//создадим еще один объект //для него пока что свойства идентичны alert('obj2.a='+obj2.a)//1 .свойство берется из самого объекта alert('obj2.b='+obj2.b)//2 .свойство берется из прототипа объекта //переопределим его свойства: obj2.a=11 obj2.b=12 //посмотри как это повлияло на первый и второй объекты: alert('obj.a='+obj.a)//1 .свойство берется из самого объекта.никакого влияниея второго объекта alert('obj.b='+obj.b)//2 .свойство берется из прототипа объекта.никакого влияниея второго объекта alert('obj2.a='+obj2.a)//11 .свойство берется из самого объекта alert('obj2.b='+obj2.b)//12 .свойство берется из самого объекта.прототип остался неизменным //как видим изменение своства b второго объекта никак не повлияло на прототип, и на первый объект. //ну, совсем никак //теперь изменим свойство b у ихнего прототипа: constr.prototype.b=22 alert('!obj.b='+obj.b)//22 alert('!obj2.b='+obj2.b)//12 //как видим изменение прототипа затронуло только первый объект //потому что у первого свойство b не было переопределено .а у второго было. //поэтому первый все еще берет свойство из протипа, а вот второй берет уже собственное свойство b, которое мы назначили выше //попробуем поменять свойство prototype у функции-конструктора constr.prototype={'b':32} alert('obj.b='+obj.b)//22 alert('obj2.b='+obj2.b)//12 //как видим смена свойства prototype у функции-конструктора никак не сказалась на УЖЕ созданных объектах. //зато все последующие созданные объекты будут иметь НОВЫЙ прототип, никак не связанный с прототипом старх объектов obj3=new constr() alert('obj3.b='+obj3.b)//33.это свойство его прототипа.но не прототипа предыдущих объектов alert([ obj.__proto__== obj2.__proto__, obj3.__proto__== obj.__proto__, obj3.__proto__== obj2.__proto__ ])//TRUE,FALSE,FALSE //как видим у первых двух объектов прототип совпадает между собой. //а вот у третьего не совпадает ни с прототипом первого, ни с прототипом второго PS запускать для наглядности в Mozilla также будет легче, если вы поставите себе firebug, и замените все alert на console.log |
надеюсь этот пример разъяснит вам на пальцах, как это все работает.
я старался |
Цитата:
Молодец, хорошо описал. ;) |
Dmitry A. Soshnikov,
спасибо.исправил |
2 Gvozd > Исправьте и у меня , если что далее неверно :
Прототип(тип или класс родителя) объекта - это свойство prototype конструктора объекта ( объект.constructor.prototype ). На примере встроенного объекта Array можно сделать следующие высказывания: 1) Array.prototype // - ссылка на прототип(или что то же самое тип родителя) объектов, создаваемых с помощью конструктора Array, который сам является объектом типа Function ; Т.е. : Function===Array.constructor // - конструктор Array - есть Function (или , что то же самое, - его тип есть Function) Function.prototype===Array.constructor.prototype // - тип родителя объекта Array (являющегося конструктором) тоже определяется через свойство prototype его конструктора ( которое == function prototype() {[native code] } ) 2) Array.prototype.constructor===a.constructor // - ссылка на конструктор объектов а, которые имеют тип Array (,где var a=new Array() ) 3) Array.prototype===a.constructor.prototype // - прототип (тип родителя) объекта а [strike](== function Array() { [native code] } )[/strike] 4) Array===a.constructor // - [strike]тип (класс) объекта а [/strike]- объект-конструктор объекта а ( == function Array() { [native code] } ) |
Цитата:
во вторых тип объекта и прототип - разные вещи. тип объекта определяется каким конструктором он был создан. а прототип свойством prototype конструктора, на момент создания объекта ну, и в третьих родителем объекта является его прототип, а не его конструктор прототип объекта-это не тип и не класс объекта, а объект, постоянно висящий в памяти, и который можно считать родителем этого объекта ---------------------------------------------------------------------- Цитата:
у Array прототип не Function, а объект созданный с помощью Function Array.__proto__!=Function Array.__proto__==(function(){})//тут на самом деле будет FALSE.но суть примерно такая, что прототип конструктора Array - пустая функция Таким образом Function - конструктор конмтруктора Array, а пустая функция(не любая, а вполне такая определенная, висящая в памяти со старта скрипта, и созданная интепретатором) яляется прототипом конструктора Array ---------------------------------------------------------------------- Цитата:
Array.prototype.constructor===a.constructor===Arra y то есть конструктор у объекта a и у его прототипа одинаков, и это есть функция Array ---------------------------------------------------------------------- Цитата:
Array - тип родителя объекта a( и при этом тип самого объекта a) Цитата:
Array.prototype===a.constructor.prototype == new Array()//опять-таки тут будет на самом деле FALSE. по сути дела заместо (new Array()) должен быть так же висящий в памяти объект типа Array ---------------------------------------------------------------------- половина исправлений была скорее на терминологию |
Количество слов "prototype" в ветке взрывает мозг. :dance:
сорри за оффтоп |
Zeroglif,
ты мне тут это.того. не загаживай такую прелестную ветку оффтопом:rolleyes: PS на самом деле мне эта тема очень нравится. гораздо приятней помочь человеку разобратся в такой довольно нелегкой вещи как прототипирование(я сам статью Кантора перечитывал раза три, прежде чем до меня тогда начало доходить.и вообще, я сперва думал, что prototype==[[prototype]]), чем заставлять людей хоть немного потрудится самим, после того как объясниш ему алгорит простейшей задачи. во всяком случае тут видна усердная работа человека и стремление разобратся, а не получить решение конкретной задачи "на блюдечке" |
Цитата:
|
Zeroglif,
вообще-то я думал, что obj.prototype==obj.[[prototype]] ну или как-то так. уже точно не помню, что творилось у менгя в голове но точно помню, как три или четыре раза перечитывал статью короче, мне эта тема не сразу, и не так просто далась |
Цитата:
|
Zeroglif,
хватит ломать мне мозг. он и так разрушен радио "Воруй, Убивай" и проектом "Нежное Это" а тут еще прототипы, до кучи |
Цитата:
//var constr = function() {} ; /* или так */ var constr = new Function() /* или так */ function constr() {} var constr = new Function() // constr - есть объект(экземпляр) типа(класса) Function ( Function - это не родитель объекта constr , а его тип(класс) ) // - кроме создания объекта-конструктора constr еще выполяется следующее : // - создаётся новый объект-прототип (ссылка на который заносится в constr.prototype) ; // - значением свойства constructor этого объекта становится создавший его объект-конструктор (constr.prototype.constructor=constr); // - значением свойства prototype объекта-конструктора становится вновь созданный объект - А что это за объект ??- непонятно. var a=new constr() // a - есть объект(экземпляр) типа(класса) constr ( constr - это не родитель объекта a , а его тип(класс) ) document.write([ // Иерархия объектов пользователя (прикладных объектов)--------- : a.constructor.prototype===a.__proto__, a.constructor.prototype===constr.prototype, a.__proto__===constr.prototype, // родитель объекта a (ссылка на родителя содержится в свойстве prototype конструктора объекта a) //constr.prototype.constructor, // ==function anonymous() { } <- конструктор родителя constr.prototype.constructor.prototype=='[object Object]' , constr.prototype.__proto__ =='[object Object]', constr.prototype.constructor.prototype===constr.prototype.__proto__ , // FALSE ?? constr.prototype.constructor===constr, // TRUE (значением свойства constructor родителя будет создавший его объект-конструктор constr ); // К слову, также не понятно, почему : a.__proto__.constructor===a, //FALSE , т.к. а - не есть объект-конструктор ?? constr.prototype.__proto__.__proto__===null, // TRUE - вершина constr.prototype.__proto__===Object.prototype, // TRUE ]) Т.е. я пытался, но мне не удалось построить стройную и понятную, где был бы понятен каждый объект в цепи наследования, иерахию объектов от a к родоначальнику Object.prototype, у которого уже нет родителя. |
Цитата:
__________________________________________________ ______ Цитата:
потому что это разные объекты //конструктор свойства prototype конструктора является сам конструктор constr.prototype.constructor==constr//из этого следует => constr.prototype.constructor.prototype==constr.prototype //такую конструкцию можно дополнять циклично на любой уровень вложенности //-------------------------------------------------------------- прототипом свойства prototype конструктора является свойство prototype конструктора Object. constr.prototype.__proto__==Object.prototype //-------------------------------------------------------------- constr.prototype!=Object.prototype //зато: constr.prototype.__proto__==Object.prototype //то есть прототипом свойства prototype является свойство prototype Object() __________________________________________________ ______ Цитата:
a //объект a.__proto__ //прототип объекта(является экземпляром типа constr) a.__proto__.constructor //конструктор прототипа a.__proto__.constructor==a.constructor//у прототипа и у объекта общий конструктор a.__proto__.constructor==constr//и этот конструктор - функция constr, а не объект a __________________________________________________ ______ на закуску: var a=new constr() // a - есть объект(экземпляр) типа(класса) constr ( constr - это не родитель объекта a , а его тип(класс) ) alert(a.__proto__==constr.prototype)//TRUE constr.prototype=new constr() alert(a.__proto__==constr.prototype)//уже FALSE, так как прототип объекта остался тем же, а вот свойство prototype его конструктора уже изменилось __________________________________________________ ______ По поводу же иерахии напишу так: var constr = new Function() var a=new constr() console.log([ a.__proto__==constr.prototype, //прототип объекта constr.prototype.__proto__==Object.prototype, //прототип прототипа объекта Object.prototype.__proto__==null //прототип прототипа прототипа объекта уже не существует ]) |
Цитата:
Цитата:
|
Gvozd,
Цитата:
|
Цитата:
constr.prototype.constructor===constr а у объекта-НЕконструктора это НЕтак . короче , заплутал малость, решил , что constr.prototype=constr.__proto__ Т.е. непонятка мешает : отчего же свойство constructor недоступно для объекта, не являющегося конструктором ? PS. Остальное позже разберу. |
Цитата:
"не общий конструктор, а один и тот же объект, к которому приведёт свойство constructor" (хотя, конечно, это и имелось в виду) |
Просто это важные по смыслу словосочетания "прототип объекта" и "конструктор объекта", но из-за перегруженности терминов они часто непроизвольно подменяются "прототипом функции" или "конструктором прототипа", ломая картинку наследования...
|
Цитата:
вообще-то он доступен: alert(a.constructor)//зависит от способа создания конструктора //если var constr = new Function(), то будет анонимная функция //если function constr(){} , то будет именованая функция constr() console.log(a.constructor==constr)//TRUE |
Часовой пояс GMT +3, время: 05:23. |
|