А я вот не в курсе. Это как-то оговаривалось? Где-то описывался алгоритм ==?
> если типы разные — то объекты разные, если справа и слева один объект — то они уж точно равны :-) Вот если типы одинаковые и объекты разные — можно двигаться дальше.
Почему «если типы разные»? Почему 1 == '1' при разных типах не может быть true, если типизация динамическая? Более того, можно ввести оператор like и выдавать true на {a: 1, b: 2, c: 3} like {a: 1, b: 2}. При этом может быть одинаковый тип, но объекты разные. {a: 1} == {a: 1} — с какой стати должно быть true?
> и даже a===a может быть false — что как бы несколько дико
NaN == NaN // false (и это оговорено), а еще кто?
> Хидден-классы их не реализуют ни разу
А почему Вы так категорично утверждаете? В Ruby, например, так примеси и реализованы. По include'у создается хидден-класс, который вклинивается первым в цепь поиска.
> ещё раз на пример с ios/istream/ostream/iostream, пожалуйста
Подробней расскажите, я не понял, что Вы имеете в виду.
> Классическая тройка эквивалентностей из Lisp'а не подойдёт?
Я с Lisp'ом знаком поверхностно, но сейчас почитал про эти три оператора. И что? Конкретная реализация конкретной системы. Кто сказал, что во всех остальных должна быть такая же? А еще, кроме Лиспа?
> и другие подобные извращения — притягивание за уши клооп к js.
Конкретно, пожалуйста, конкретно. Где, в каком месте и почему что-то там является извращением? Это Ваше ИМХО? Или кто-то Вам сказал?
По поводу «клооп». Про динамические классовые организации слышали? Сравнения с моделью JS делали? Сходство видели? А разницу? И кто там кого и куда «за уши тянет»?
> Но это не применение синглтона :)
Смотря, что такое синглтон. Если для использования этого термина обязательно нужна сущность «класс» (а кто Вам это сказал?) — тогда можно не употреблять этот термин вообще. Тем, не менее, можно {} назвать, например, Singleinstance (и создать ее хоть отложено, хоть переотложено). Правда, для пущей наглядности, можно обернуть в функцию со «статическим» свойством — тогда уж точно отложено можно создавать/возращать нужный объект.
«Синглтон» — всего лишь термин, для чье-то красивой реализации одиночности объекта. И «клооп» здесь особой роли не играет. А в JS нет никаких синглтонов, но можно называть одиночные объекты «Одиночками».
То, что в статье под одну гребенку подогнаны и и FunctionDeclaration и FunctionExpression — это, конечно, недочет. А то, что там какая-та реализация обрабатывает «по-своему» поведение FunctionExpression — это дело десятое.
Что значит «не синглтон»? Причем здесь классовое ООП (я правильно понял «клооп»?). Где четкое определение синглтона (настолько четко, что дальше ни шагу)?
> Отсюда и непонимание про костыли и уши.
Ну, я все-таки снова попрошу объяснить. Ну а иначе — какой смысл просто так что-то говорить?
> В ранних версиях нельзя было даже надёжно сравнить два объекта! Операторы === и !== появились в версии 1.3!
а, т.е. был один ==, который не учитывал типы? и 1 == '1' было false, да? Или что? Вообще, не известно что было? Что значит «нельзя было надежно сравнить»? А как в других («не дерьмовых») языка дело обстояло в то время?
> В ранних версиях объекты функций прямо так и принадлежали к объекту «функция» и к ним был доступ снаружи (это отменили не то в версии 1.4, не то в 1.5).
Что имеется в виду? Я не совсем понял. Переменные в скопе функции и к ним был доступ? Или что за «объекты функции, к которым был доступ снаружи»? Уточните.
> И вообще там было много чудес.
Как и в любой разрботке, которая эволюционирует. А какие Вы видели «недерьмовые» эталонные разработки?
> Которые, в частности, до сих пор не позволяют сделать нормальный многопоточный движок…
А какие «чудеса» не позволяют?
> Эта лазейка не позволяет изменять поле [[Prototype]] (которое, кстати, можно было бы разрешить делать не только указателем на объект, но и, скажем, массивом — на скорость это особо не повлияло бы, но зато сделало бы mix-in'ы возможными).
В смысле? Несколько объектов (массив) в одном звене цепи наследования? А какая разница:
obj -> obj1 -> [obj2, obj3] -> obj4
или
obj -> obj1 -> obj2 -> obj3 -> obj4
Или я не правильно понял? И почему «тогда бы были доступы примеси»? Где точный алгоритм реализации примеси? Примесь может быть реализована и вклиниванием хидден-класса в цепь наследования и, так же, расширением самого объекта родными слотами.
> Я боюсь вы даже не поняли о чём я
О, пожалуйста, не переживайте, я Вас успокою — я понял. :)
> не имеет никакого отношения к оператору эквивалентности и наличие === отнюдь не означает что == не должно быть отношением эквивалентности
Почему не означает? Реализаций — много, идей — еще больше. Как реализовали, ==, так, вероятно, и задумывалось. А покажите пример, эквивалентности объектов в разных языках. Мне интересно.
> Или можно было бы пойти в другом направлении: большей строгости (см. проект JavaScript 2.0). А сегодня JavaScript — это ни рыба, ни мясо.
Если будет строго — это будет «рыба»? Или «мясо»? Почему? Откуда Вы взяли это утверждение?
> Я просто наблюдал за этими языками в то время как они создавались и за попытками сделать из дерьма конфетку. Результат… тот ещё.
А с JavaScript'ом-то где дерьмо было? Черт с ними, со старыми версиями PHP, где объекты по значению передавались (кстати, какая такая священная книга написала, что они обязательно должны передаваться по ссылке? Ну — во многих языка — по ссылке, значит по ссылке — ок, они «исправились» в новых версиях).
> Например пресловутая модель на основе протипов: штука простая и красивая но кому и зачем пришла в голову идея что прямой доступ к полу __proto__ людям не нужен? В результа вместо простых и понятных манипуляций приходится изобретать кучу странных приёмов.
Моделей куча, организаций еще больше. Разве, во всех языках порожденный объект имеет доступ к своему конструктору (классу)? И прототипы тут не при чем. Например, в Python, объекты имеют доступ к классу через аналогичное свойство __class__. К тому же — лазейку оставили — через .constructor.prototype (это «куча странных приемов»?)
> Но, конечно, переплюнуть PHP где до сих пор оператор == — не отношение эквивалентности
А в JS тоже. Поскольку ни там, ни там строгой типизации нет. Но дерьмо ли это? Для эквивалентности в обоих языках есть ===.
> зато у объекта есть свойство constructor, которое указывает на функцию-конструктор
Тоже (опечатка, наверное) не точно в этом моменте. Сначала правильно пишите, что свойство constructor — это свойство прототипа конструктора. А затем говорите, что это свойство порожденного объекта (тогда как это свойство не родное и будет найдено в прототипе).
> а всё потому что язык не был спроектирован, а был слеплен из разных кусков, которые довольно странно взаимодействуют между собой. Хуже него — только PHP, даже Perl — и тот не так ужасен.
Ой, с удовольствием послушаю-ю :) Подождите, попкорн только возьму и поудобней усядусь =) Шутка, не обижайтесь :)
А, если серьезно, то — расскажите, почему Вы так думаете, откуда, на основе чего Вы пришли к таким выводам?
> Вот и спрашивается, чем B.parent.apply(this, arguments) лучше по сравнению с this.init_A(arguments);
Или я что-то упустил, или изначально не про это спрашивалось? :) Изначально спрашивалось, как передавать параметры в конструктор и не делать никаких проверок в этом одном и том же конструкторе, который используется и для порождения и для обеспечения наследования.
Касаемо Вашего текущего вопроса про «init_A»: в случае с B.parent — мы не привязываемся к именам родительских сущностей («А», «Bla», «SuperBla»). В принципе, можно даже и к «B» не привязываться, если общаться через «this.constructor.parent».
А зачем нам «конструктор» и «сделай_на_основе_конструктора»? Ладно бы Вы штамповали каскадно объекты через фабрику, но это здесь — уже создана «порождающая сущность» (конструктор), но потом еще и «порождающая-порождающая сущность».
Другой вопрос, когда конструктор обертывают — там нет никаких привязок к именам типа «bird», «make_a_bird» и т.д. + еще и связать прототипы можно внутри этой обертки.
Создавать же wrapper для каждого конструктора вручную — это лишнее.
> тандем из функции и её прототипа вполне можно называть классом ибо удовлетворяет всем признакам класса.
только ты уточняй, — «всем признакам динамического класса» (потому что те, кто не знаком с динамическими объектами и классами, могут не сразу понять). Ну и, естественно, лучше уточнять (для избежания пустых холиворов), что стандарт понятия «класс», как «отдельная сущность для порождения объектов» — не описывает.
> А смысл городить такие конструкции, если можно просто не делать в конструкторах ничего, кроме инициализации свойств дефолтными значениями?
Ну компромисс — есть компромисс. И подобных компромиссов «а смысл?» можно тогда в любом месте напихать (тогда вообще, смысл может отпасть и достаточно будет линейного (даже не процедурного)) программирования (безо всяких классов и прототипов).
К тому же, иногда, кто-то в конструкторе (или методе init (если еще и для конструктора будет враппер) — не важно) может выдать системное сообщение.
> Ведь если цель — сократить объем кода и избежать лишних сущностей, то метод с wrapper все равно не позволяет ее достигнуть.
Ну вот в эти моменты люди и начинают писать функции-обертки (и часто называют их «классами»), где эти манипуляции с __wrapper'ами скрыты, но обеспечивают наследование. Естественно, никто не заставляет каждый раз писать этот кусок кода — вынесете его в обертку и создавайте объекты через нее (это всего лишь улучшение code reuse).
А я вот не в курсе. Это как-то оговаривалось? Где-то описывался алгоритм ==?
> если типы разные — то объекты разные, если справа и слева один объект — то они уж точно равны :-) Вот если типы одинаковые и объекты разные — можно двигаться дальше.
Почему «если типы разные»? Почему 1 == '1' при разных типах не может быть true, если типизация динамическая? Более того, можно ввести оператор like и выдавать true на {a: 1, b: 2, c: 3} like {a: 1, b: 2}. При этом может быть одинаковый тип, но объекты разные. {a: 1} == {a: 1} — с какой стати должно быть true?
> и даже a===a может быть false — что как бы несколько дико
NaN == NaN // false (и это оговорено), а еще кто?
> Хидден-классы их не реализуют ни разу
А почему Вы так категорично утверждаете? В Ruby, например, так примеси и реализованы. По include'у создается хидден-класс, который вклинивается первым в цепь поиска.
> ещё раз на пример с ios/istream/ostream/iostream, пожалуйста
Подробней расскажите, я не понял, что Вы имеете в виду.
> Классическая тройка эквивалентностей из Lisp'а не подойдёт?
Я с Lisp'ом знаком поверхностно, но сейчас почитал про эти три оператора. И что? Конкретная реализация конкретной системы. Кто сказал, что во всех остальных должна быть такая же? А еще, кроме Лиспа?
Конкретно, пожалуйста, конкретно. Где, в каком месте и почему что-то там является извращением? Это Ваше ИМХО? Или кто-то Вам сказал?
По поводу «клооп». Про динамические классовые организации слышали? Сравнения с моделью JS делали? Сходство видели? А разницу? И кто там кого и куда «за уши тянет»?
> Но это не применение синглтона :)
Смотря, что такое синглтон. Если для использования этого термина обязательно нужна сущность «класс» (а кто Вам это сказал?) — тогда можно не употреблять этот термин вообще. Тем, не менее, можно {} назвать, например, Singleinstance (и создать ее хоть отложено, хоть переотложено). Правда, для пущей наглядности, можно обернуть в функцию со «статическим» свойством — тогда уж точно отложено можно создавать/возращать нужный объект.
«Синглтон» — всего лишь термин, для чье-то красивой реализации одиночности объекта. И «клооп» здесь особой роли не играет. А в JS нет никаких синглтонов, но можно называть одиночные объекты «Одиночками».
Что значит «не синглтон»? Причем здесь классовое ООП (я правильно понял «клооп»?). Где четкое определение синглтона (настолько четко, что дальше ни шагу)?
> Отсюда и непонимание про костыли и уши.
Ну, я все-таки снова попрошу объяснить. Ну а иначе — какой смысл просто так что-то говорить?
да нет, в первых двух случаях, как раз-таки получаются не «объект типа функция», а «объект типа объект».
а, т.е. был один ==, который не учитывал типы? и 1 == '1' было false, да? Или что? Вообще, не известно что было? Что значит «нельзя было надежно сравнить»? А как в других («не дерьмовых») языка дело обстояло в то время?
> В ранних версиях объекты функций прямо так и принадлежали к объекту «функция» и к ним был доступ снаружи (это отменили не то в версии 1.4, не то в 1.5).
Что имеется в виду? Я не совсем понял. Переменные в скопе функции и к ним был доступ? Или что за «объекты функции, к которым был доступ снаружи»? Уточните.
> И вообще там было много чудес.
Как и в любой разрботке, которая эволюционирует. А какие Вы видели «недерьмовые» эталонные разработки?
> Которые, в частности, до сих пор не позволяют сделать нормальный многопоточный движок…
А какие «чудеса» не позволяют?
> Эта лазейка не позволяет изменять поле [[Prototype]] (которое, кстати, можно было бы разрешить делать не только указателем на объект, но и, скажем, массивом — на скорость это особо не повлияло бы, но зато сделало бы mix-in'ы возможными).
В смысле? Несколько объектов (массив) в одном звене цепи наследования? А какая разница:
obj -> obj1 -> [obj2, obj3] -> obj4
или
obj -> obj1 -> obj2 -> obj3 -> obj4
Или я не правильно понял? И почему «тогда бы были доступы примеси»? Где точный алгоритм реализации примеси? Примесь может быть реализована и вклиниванием хидден-класса в цепь наследования и, так же, расширением самого объекта родными слотами.
> Я боюсь вы даже не поняли о чём я
О, пожалуйста, не переживайте, я Вас успокою — я понял. :)
> не имеет никакого отношения к оператору эквивалентности и наличие === отнюдь не означает что == не должно быть отношением эквивалентности
Почему не означает? Реализаций — много, идей — еще больше. Как реализовали, ==, так, вероятно, и задумывалось. А покажите пример, эквивалентности объектов в разных языках. Мне интересно.
> Или можно было бы пойти в другом направлении: большей строгости (см. проект JavaScript 2.0). А сегодня JavaScript — это ни рыба, ни мясо.
Если будет строго — это будет «рыба»? Или «мясо»? Почему? Откуда Вы взяли это утверждение?
Почему? Почему, если мне нужен просто единичный объект:
var obj = {a: 10, b: function () {}, c: 20};
> Эдак можно вообще все сложные объекты так создавать «для подстраховки».
Не ясно.
> ИМХО, если такая ситуация возникла, скорее всего, нужно пересмотреть архитектуру приложения.
Почему? Почему, если мне нужен просто единичный объект:
var obj = {a: 10, b: function () {}, c: 20};
> Считаете иначе — приведите пример, если не трудно.
Да можно по-разному считать и если разные мнения технологически обоснованы — можно использовать все эти мнения и подходы.
Я хотел узнать, что там за «костыли», «уши» и «другие средства»?
А почему именно function, а не просто var b = {};? Коль скоро, это «синглтон»? {} по действиям алгоритма быстрее, чем создание объекта function.
Что Вы имеете в виду? Можно подробней, мне интересно.
А с JavaScript'ом-то где дерьмо было? Черт с ними, со старыми версиями PHP, где объекты по значению передавались (кстати, какая такая священная книга написала, что они обязательно должны передаваться по ссылке? Ну — во многих языка — по ссылке, значит по ссылке — ок, они «исправились» в новых версиях).
> Например пресловутая модель на основе протипов: штука простая и красивая но кому и зачем пришла в голову идея что прямой доступ к полу __proto__ людям не нужен? В результа вместо простых и понятных манипуляций приходится изобретать кучу странных приёмов.
Моделей куча, организаций еще больше. Разве, во всех языках порожденный объект имеет доступ к своему конструктору (классу)? И прототипы тут не при чем. Например, в Python, объекты имеют доступ к классу через аналогичное свойство __class__. К тому же — лазейку оставили — через .constructor.prototype (это «куча странных приемов»?)
> Но, конечно, переплюнуть PHP где до сих пор оператор == — не отношение эквивалентности
А в JS тоже. Поскольку ни там, ни там строгой типизации нет. Но дерьмо ли это? Для эквивалентности в обоих языках есть ===.
Чем еще эти языки ужасны?
Тоже (опечатка, наверное) не точно в этом моменте. Сначала правильно пишите, что свойство constructor — это свойство прототипа конструктора. А затем говорите, что это свойство порожденного объекта (тогда как это свойство не родное и будет найдено в прототипе).
Ой, с удовольствием послушаю-ю :) Подождите, попкорн только возьму и поудобней усядусь =) Шутка, не обижайтесь :)
А, если серьезно, то — расскажите, почему Вы так думаете, откуда, на основе чего Вы пришли к таким выводам?
Дело генерации. Или Вы на счетах считаете, а не на компьютере?
Один из лозунгов «какой-то» философии:
Или я что-то упустил, или изначально не про это спрашивалось? :) Изначально спрашивалось, как передавать параметры в конструктор и не делать никаких проверок в этом одном и том же конструкторе, который используется и для порождения и для обеспечения наследования.
Касаемо Вашего текущего вопроса про «init_A»: в случае с B.parent — мы не привязываемся к именам родительских сущностей («А», «Bla», «SuperBla»). В принципе, можно даже и к «B» не привязываться, если общаться через «this.constructor.parent».
А зачем нам «конструктор» и «сделай_на_основе_конструктора»? Ладно бы Вы штамповали каскадно объекты через фабрику, но это здесь — уже создана «порождающая сущность» (конструктор), но потом еще и «порождающая-порождающая сущность».
Другой вопрос, когда конструктор обертывают — там нет никаких привязок к именам типа «bird», «make_a_bird» и т.д. + еще и связать прототипы можно внутри этой обертки.
Создавать же wrapper для каждого конструктора вручную — это лишнее.
только ты уточняй, — «всем признакам динамического класса» (потому что те, кто не знаком с динамическими объектами и классами, могут не сразу понять). Ну и, естественно, лучше уточнять (для избежания пустых холиворов), что стандарт понятия «класс», как «отдельная сущность для порождения объектов» — не описывает.
Ну компромисс — есть компромисс. И подобных компромиссов «а смысл?» можно тогда в любом месте напихать (тогда вообще, смысл может отпасть и достаточно будет линейного (даже не процедурного)) программирования (безо всяких классов и прототипов).
К тому же, иногда, кто-то в конструкторе (или методе init (если еще и для конструктора будет враппер) — не важно) может выдать системное сообщение.
> Ведь если цель — сократить объем кода и избежать лишних сущностей, то метод с wrapper все равно не позволяет ее достигнуть.
Ну вот в эти моменты люди и начинают писать функции-обертки (и часто называют их «классами»), где эти манипуляции с __wrapper'ами скрыты, но обеспечивают наследование. Естественно, никто не заставляет каждый раз писать этот кусок кода — вынесете его в обертку и создавайте объекты через нее (это всего лишь улучшение code reuse).