| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > JavaScript: Общие вопросы > О свойствах и методах в объектах и прототипах |
| Автор: Burrr 29.4.2008, 21:54 | ||||
| Приветствую! Речь пойдет о статье http://karaboz.ru/2007/10/03/oop-v-java-script-klassy/. Процитирую комментарий, оставленный пользователем Zeroglif:
Вопрос: "О какой цепочке речь?". Может кто-нибудь четко объяснить механизм поиска при обращении к свойству объекта? Добавлено @ 22:04 Для пояснения приведу пример:
Как возможно, что второй вызов метода срабатывает? Точнее где теперь хранится метод, если в контексте объекта он не создавался, а прототип пуст? |
| Автор: ksnk 29.4.2008, 23:12 |
| Объект несколько сложнее, чем можно выразить средствами JavaScript Своими словами - прототип объекта при создании нового элемента копируется в скрытое поле самого объекта. Это поле, imho, доступно нам только в ощущениях, напрямую заюзать его нельзя... Свойство prototype объекта (не функции) никакого дополнительного смысла не несет, да и вообще никакого смысла не несет кроме заданного пользователем |
| Автор: Burrr 29.4.2008, 23:17 |
| ksnk 1) У объектов нет прототипа, прототипы есть только у конструкторов. 2) Если бы при создании каждого экземпляра объекта прототип конструктора записывался бы в скрытое поле объекта, то это немеряно жрало бы память, чего не наблюдается, да и смысла не было бы в такой реализации прототипирования. Добавлено @ 23:21 ksnk, правильней будет сказать "Экземпляры объекта наследуют свойства и методы от прототипа конструктора, но не имеют собственного прототипа". |
| Автор: Burrr 30.4.2008, 00:03 | ||||||||
| ksnk, нужно определиться с терминологией, иначе комментарии будут вводить в заблуждение. В JavaScript всё является объектами, но для ясности некоторые объекты следует называть иначе. И так:
правильно звучит так: "Прототип конструктора при создании экземпляра объекта копируется в скрытое поле этого конструктора". В таком свете всё становится ясно и нареканий не вызывает Только откуда взято такое утверждение? Есть чем подтвердить или это догадка?
Нет это не расточительство. Но где хранится эта предполагаемая ссылка? В экземпляре объекта или в конструкторе?
Прототип - это свойство конструктора, хранящее ссылку на объект, содержащий хеш со свойствами и методами, например, со свойством constructor, указывающего обратно на функцию конструктор.
Вы не очень понимаете что такое наследование и ваш пример - это создание 2-х экземпляров объекта одного класса, которые достают свое свойство из прототипа конструктора, в котором в своб очередь стоит ссылка на глобальный oбъект b = {} и не более того. Добавлено @ 00:09 Сразу поясню насчет наследования: Наследование - это понятие из ООП, подразумевающее возможность порождать один класс от другого с сохранением свойств-методов класса родителя, возможностью их переопределения и добавленич новых свойств-методов. За неимением классов, реализация наследования через прототип в JavaScript от одного конструктора другому - не такая уж простая задача. |
| Автор: Burrr 30.4.2008, 00:29 |
| Ага, а вот и ответ на мой первоначальный вопрос: http://www.javascript.ru/tutorial/object/inheritance#svoistvo-prototype-i-prototip |
| Автор: ksnk 30.4.2008, 01:20 | ||
Хмм... Для моего примера - obj - конструктор, b - прототип, a - объект. Согласно отквоченному утверждению, после строки a= new obj(); в obj будет содержаться скрытая ссылка на b. Что будет если заменить obj.prototype и сделать генерацию нового объекта? Или конструктор - более сложная субстанция? imho, каждый объект содержит по крайней мере два скрытых списка - список конструкторов, с которым работает инструкция instanceof и список прототипов (поле __proto__ для FF ), по которому производится поиск свойств этого объекта. Формируются эти списки в момент выполнения new. Ну и конечно, для хранения всего этого списка в каждый новый объект достаточно добавить пару ссылок... |
| Автор: AKS 30.4.2008, 07:30 | ||||||||||||||
Я, конечно, понимаю, что найти что-то стоящее не так-то просто. Слово javascript в строке поиска вернет что-нибудь, типа "Центральный Javascript-ресурс" (кто его сделал центральным?), а слово prototype так вообще вернет результат не для слабонервных. Тем не менее, можно, проявив смекалку, набрать какую-нибудь хитрую комбинацию слов, одним из которых задать известное имя. Тогда может попасться ссылка на форум dklab, а там уже прямая дорога к шпаргалке всех времен и народов — http://forum.dklab.ru/viewtopic.php?p=102575#102575. Читать же то, что написано на "центральных ресурсах", где авторы по наитию описывают все своими словами, пытаясь наобум попасть пальцем в небо, довольно утомительное занятие. Ведь надо еще догадаться, что имеется ввиду, когда используется ненормативная лексика (в рамках ECMAScript Language Specification) или собственные фантазии вместо фактов. Например:
Указывает, от кого наследовать, значит? Что и от кого будет наследовано вот здесь:
? Или как уразуметь вот это:
"Ставите", "говорите"? Бо-о-о-же мой! А вот еще:
Далее картинка, изображающая:
И в заключении:
Вот как догадаться после таких объяснений, кто и где там "стоит" или "находится"? Добавлено @ 07:38
Зачем объекту содержать список конструкторов, если instanceof конструкторами "не интересуется" (они могут быть полезны лишь в качестве операнда)? |
| Автор: ksnk 30.4.2008, 08:22 |
? Каким, интересно образом вот такая конструкция может сработать a=new Array(); alert(a instanceof Array);, есль объект a не будет содержать ссылку на функцию Array? |
| Автор: AKS 30.4.2008, 09:42 | ||||||||
Этот instanceof мог бы выглядеть примерно так (абстрактно):
, или в FF вот так:
Так что объекту a не надобности в "ссылках" на функцию Array. Именно этот принцип позволяет вот такому выражению быть истиной:
|
| Автор: ksnk 30.4.2008, 10:04 | ||
Таки да... Видимо, так оно и сделано... Правда выглядит это как-то стремно...
|
| Автор: AKS 30.4.2008, 10:17 |
А какие именно результаты смущают? Или "стремен" сам оператор instanceof? Если оператор, то о нем уже давно все сказано... |
| Автор: ksnk 30.4.2008, 10:40 |
| Я интуитивно расчитываю, что конструкция a instanceof obj будет выдавать true всегда, а конструкция a instanceof obj1 будет выдавать всегда false... |
| Автор: Zeroglif 30.4.2008, 11:45 |
| Все беды, братцы, от переизбытка в javascript самого слова "prototype": - object's prototype; - prototype-based inheritance; - each constructor has a prototype property - every constructor has an associated prototype; - constructor has an implicit reference to the prototype; - implicit prototype chain; - prototype is an object; - ... Если сюда ещё добавить и общий смысл - prototype (образец, прототип) и вспомнить заодно про одноимённую библиотеку, с помошью которой про прототип гуглить уже бесполезно, то картинка удручает... |
| Автор: AKS 30.4.2008, 11:56 | ||||
С этим, вроде бы, жить можно (потихоньку, не высовываясь
Интуиция может и подвести (тогда, когда конструкторы ассоциируются с классами). |
| Автор: Zeroglif 30.4.2008, 12:12 | ||
К сожалению, терминология языка очень помогает этой интуиции: 'new', 'instanceof', 'instances' - это как-то не очень подчёркивает прототипную суть. |
| Автор: AKS 30.4.2008, 12:44 | ||||||
Ну а что делать - что есть, то есть. "Папа" о своем "детище" (с явной неприязнью):
Все к тому, что "слепили" наспех. Однако это не помешало тому, чтобы http://javascript.crockford.com/popular.html. Отчасти потому, что:
, однако, немаловажно:
|
| Автор: ksnk 30.4.2008, 13:02 |
| Автор: AKS 30.4.2008, 14:10 | ||
Во-во, о том и я. Если считать, что функции-конструкторы — это классы в js, то так и будет "думаться интуитивно", что у объекта может быть несколько конструкторов. На самом же деле конструктор один. Ведь конструктор — он и в Африке конструктор. Сконструировал, и пошел (как говаривает Zeroglif) лесом. А instnceof обязан исследовать "генеалогию" объектов. Как это сделать, если нет классов? Обращаться к конструктору? С какой стати, если наследственные связи реализованы через прототипы (своего "папу" объект не "помнит" — (new function () {}).[[Class]] => 'Object'). Значит через них, через прототипы. Причем что-то запоминать (кто был в prototype у функции-конструктора когда-то) — это не в природе js. Отсюда и резульаты — всякий раз могут быть разные, ведь вычисляется то, что есть в данный момент... |
| Автор: Zeroglif 30.4.2008, 14:58 |
Brendan уже живёт в эру ES4, ради этого светлого будущего он готов перечислять недостатки ES3 часами, с картинками и графиками. Центральный? Тогда блок рекламы. Всем без исключения нужно пройти http://javascript.ru/node/668/quiz/start "Основной Javascript" и... внимание... посчитать, сколько там неправильных правильных ответов. Если объект может быть и instanceof Одного, и instanceof Другого, а конструктор при этом всего один, то под каким термином тогда спрятаться? |
| Автор: AKS 30.4.2008, 15:22 |
Ха, наверно так и есть! Если что, то это не я так его "обозвал" - там титл такой: "Центральный Javascript-ресурс. Учебник с примерами скриптов. Форум. Книги и многое другое" ("многое другое" надо было в первую очередь пустить Оператор как должен называться? Или что? Если instanceof, то он ведь должен сообщить, наследует ли объект от какой-либо структуры или нет (в js к реализации подошли "творчески" - ни тем, ни другим) . Ну а по поводу конструкторов - сколько их вообще у объекта бывает-то в языках программирования? |
| Автор: Zeroglif 30.4.2008, 15:41 |
Не, ksnk, глядя на instanceof, интуитивно хочет сказать "несколько конструкторов у объекта", но AKS ему правильно в общем-то намекает, что "не несколько, а один" конструктор. Отсюда вопрос, как коротко терминологически описать ситуацию, чтоб без классовой терминологии, но понятно. Если не конструкторов несколько, то чего тогда? Функций (без акцента на слово конструктор)? "Классов"(в кавычках!)? Подтипов? |
| Автор: ksnk 30.4.2008, 15:53 | ||
Не догоняю я чего-то такие намеки? В том примере, который я приводил последний раз, у объекта а два конструктора obj и obj1! При срабатывании обоих конструкторов появится объект, являющийся наследником от b. Тому в ООП'е есть тьма аналогий итого - что-же такое конструктор, который только один? Я-то уже как-то привык называть конструктором ту функцию, которую надо подпихнуть справа к оператору new ;-) |
| Автор: AKS 30.4.2008, 16:06 | ||||||||
Из предложенных вариантов можно было бы выбрать "классов" в больших, больших таких кавычках. Что тут можно подразумевать под "классами" в кавычках? А как-раз их аналоги - структуры, которые обеспечивают наследование. Это - прототипы. Сколько прототипов у объекта в цепи, например:
столько и будет допустимо операндов справа для instanceof, чтоб была истина. Сначала сравнивить, например:
потом сравнить:
Вот и выходит, что вроде два конструктора, а на самом деле сравниваются-то прототипы. Такой вот он, instanceof (с "изюминкой"). Или не так? Добавлено @ 16:08
Так ведь при "срабатывании обоих конструкторов" появятся два объекта, и у каждого будет свой конструктор (смотря который сработал)! Только не то, чтобы "будет конструктор". Конструктор отработал - и все (дело сделано - концы в воду |
| Автор: ksnk 30.4.2008, 16:16 |
Угу... Проблема, видимо, в том, что ООП парадигма натягиваясь на JavaScript трещит и рвется во многих местах ;-). Некорректно рассуждать о языке используя отсутствующие в нем понятия ... Ага! дошло... |
| Автор: AKS 30.4.2008, 16:21 | ||
А я никогда не хотел использовать термин "класс". |
| Автор: dsCode 30.4.2008, 16:25 |
| Zeroglif, AKS, сколько вас обоих ни читаю, всегда что-то новое и интересное узнаю. Спасибо! |
| Автор: Zeroglif 30.4.2008, 19:58 | ||||
Так и есть, справа подпихиваем один конструктор. ;) Всё так, только вот приходится ситуацию описывать или кодом, или цитатами из ES, не хватает лаконичности, может всё-таки вместо "классов" использовать "тип объекта" или "подтип объекта", или "объектный тип бла-бла-бла". Тогда, к примеру, конструкция (a instanceof Array) в этом контексте проверяет, "может ли объект а наследовать от объекта типа Array". То есть, если типизация значений в javascript определяет один единственный тип - type Object, то типизация самих объектов базируется на связке конструктор плюc его свойство .prototype, значением которого является соответствущий мегаважный объект... Возьмём дурацкий пример:
Технически obj может наследовать от объектов - от Foo.prototype, от Array.prototype, от Object.prototype, а словами сразу просится сказать проще: "obj наследует от прототипа Foo", и именно так говорят очень часто, что конечно же неправильно. Термин "классы" хорош краткостью, но не про нас, а вот "тип объекта" - самое то, главное - понять на чём базируется эта типизация в среде объектов и не путать с типами значений... |
| Автор: AKS 30.4.2008, 21:08 | ||||||||
Мне тоже так кажется, что "классы" - это "мимо нот". Ведь нет их в ES3. К тому же теперь, когда есть возможность "пощупать" JavaScript'овские классы благодаря http://www.ecmascript.org/download.php, это становится совершенно очевидно.
Да точно - как всегда у Вас получается предельно четко и ясно. Единственно, над чем задумался - как быть с пользовательскими функциями-конструкторами? Вот что я имею ввиду. С тем же самым Array все просто. А вот с функцией Foo может произойти такое (точнее с ее prototype):
Можно ли сказать, что "obj может наследовать от объекта типа Foo"? Тут ведь даже нельзя применить оператор instanceof. Кстати, Opera, в отличие от многих других, в случае c obj instanceof Foo сообщает какую-то ерунду - у Foo вдруг "пропадает" св-во [[HasInstance]]! Хотя это все какие-то странности, о которых и думать-то, наверно, не стоит (короче - утро вечера мудренее)... |
| Автор: Zeroglif 1.5.2008, 14:23 |
Нельзя, в данном случае obj может наследовать от объекта типа Object (технически прямиком от Object.prototype). Таков код. Применить можно, но с выбросом ошибки. Функция Foo создала объект, но при этом Foo.prototype не находится в цепи прототипов созданного объекта, и, соответственно, этот объект не может наследовать от объекта типа Foo. |
| Автор: AKS 2.5.2008, 07:42 | ||
| Zeroglif, ну, вроде, в общем и целом пока ясно. Подумал только еще вот о чем. Зачем им понадобилось описывать в документации типы объектов при помощи [[Class]]? Наверняка, для понимания было бы лучше использовать какой-нибудь [[Type]]... Ну да им виднее! А еще вот вопросец есть - может быть Вам попадалось где-нибудь разъяснение/пояснение (предистория/мотивация) того, что:
? Просто интересно... |
| Автор: Zeroglif 2.5.2008, 08:48 | ||
Это баг ES, но движки эту э... неточность дружно проигнорировали. |
| Автор: dsCode 2.5.2008, 12:54 |
| В смысле? Опечатака что ли обычная? Т.е. там должно было быть RegExp? |
| Автор: Zeroglif 2.5.2008, 13:17 | ||
То ли пропустили, то ли вставили, как-то обосновав, но потом обоснование благополучно отмерло по причине правильной (по аналогии с остальными прототипами) реализации в большинстве движков. Угу:
|
| Автор: dsCode 2.5.2008, 15:11 | ||
ну собственно, да, toString прототипа Object'a единственный, кто возвращает [[Class]] (не догадался сам проверить =)) Угу. А вообще интересно, как поступают с официальными документами, если в них находят опечатки? Что, говорят, "просто забейте и реализовывайте правильно" Спасибо =) |
| Автор: Zeroglif 2.5.2008, 16:14 |
Это скорее заумный баг, как вариант могу предложить обсуждение на https://bugzilla.mozilla.org/show_bug.cgi?id=251284, где Waldemar Horwat считает, что это преднамеренная история, мол, у прототипа не хватает квалифицирующих признаков. Сомнительное обоснование, учитывая то, что никто не определял, как именно (по каким различиям) объекты разбросаны по [Class]-ам, известен только общий смысл - "The value of a [[Class]] property is used internally to distinguish different kinds of built-in objects" и те некоторые детали, что можно почерпнуть из описания каждого объекта. Что касается сносок на ошибки, то есть http://www.mozilla.org/js/language/E262-3-errata.html, а всё остальное закостенело навечно. Вернее уже до ES4. А может это и есть "навечно"... |
| Автор: dsCode 2.5.2008, 17:14 |
| Хм... Плохо, что я еще имен практически не знаю. Кто такой Waldemar Horwat? Разработчик ES? Вернее, на каком основании он утверждающе заявлял, что это продуманная фича ES и о нехватке "properties or behaviors", чтобы [[Class]]'у прототипа RegExp'a быть RegExp'ом? К тому же, в конце беседы выяснилось, что ES согласны с имплементациями. А это значит, что это и вовсе не важно (особого веса для беседы не имело (собственно, как не столь важно и сегодня - через 4 года ;))), и не было никакой продуманной фичи, иначе бы ее, действительно, объяснили (а то одной вуалирующей фразы "для внутренних различий встроенных объектов" может быть и недостаточно)). За errat'у - спасибо (некоторые из опечаток, описанных в ней, я тоже находил). А errata - это что? Именно мозиловская версия сборника опечаток ES? Или ES все это подтвердлили и это так же официальный документ? (под "официально подтвердили" я имею в виду случай, схожий с утверждениями Waldemar Horwat, в смысле, может Waldemar Horwat все эти опечатки errat'ы сейчас подробно распишет как очень даже продуманные фичи ES "навечно"? |
| Автор: AKS 2.5.2008, 17:56 | ||||
Ага, значит "папаша" все же грозился, что очень хочет добавить исправление по этому поводу. Только потом забы(и?)л, видимо сильно увлекшись новым JavaScript'ом (вторым, или каким он у них получится). А тут, когда открылась перспектива понаделать новых багов, опечаток и т.д., то старые — это уже не та игрушка, да ну ее.
Во-во. |
| Автор: Zeroglif 2.5.2008, 18:00 | ||||
Waldemar готовил ранние драфты JS2.0/ES4 в AOL/Netscape, соответственно ES3 ему ооочень был близок, хотя непосредственно в написании ES3 он и не участвовал, участвовал, исправляюсь. Нынче он тоже принимает участие во всей этой кухне, только, если я не ошибаюсь уже в качестве дева Google. Во всяком случае, я видел его имя, когда читал их транскрипты...
Могла быть. Время точит память. Например, многие сетуют, что arguments object сдуру не сделали массивом. А почему не сделали - никто в деталях уже не помнит (где-то встречал, что NS обвинил в этом MS, дескать, это они во всём виноваты, ну, а кто же...). Причин не помнят, но точно над этим думали.
Мозилловская версия. Запросто. Надеюсь, что у них что-нибудь не сложится (как и в первый активный период). |
| Автор: AKS 2.5.2008, 18:20 |
В моей Edition 3 Final вроде бы он "засветился" (незнаю, что уж он там делал - писал или мимо проходил |
| Автор: Zeroglif 2.5.2008, 18:38 |
Хе-хе, действительно, поискал его в старых доках и исправляюсь - он участвовал во встречах TC-39 уже в 1998 году. Прости, Вова. |
| Автор: Zeroglif 2.5.2008, 19:26 | ||||
Всё, выкопал.
В общем, он предложил поправить/уточнить уже готовый final draft - они согласились. |
| Автор: dsCode 3.5.2008, 14:45 |
| Zeroglif, невероятно! =) Как вы все умудряетесь откопать? В очередной раз - спасибо за информацию. А что там насчет Math? - не совсем понятно. Какой еще "constructor property of the Math object", которые еще и равен "Math"? Ведь Math - не конструктор и не callable (не имеет ни [[Construct]], ни [[Call]]). Может это [[Class]] Math'a имелся в виду (ну просто кто еще там равен "Math")? |
| Автор: Zeroglif 3.5.2008, 23:48 | ||
Вот именно, какой такой "constructor property of the Math object", которые еще и равен "Math"? Совсем они там оборзели, понаписали всякую ересь... з.ы. don't know |
| Автор: dsCode 4.5.2008, 11:33 |
| А и действительно, это какой-то обрывок фразы, - не известно, что там имелось в виду. |