Как стать автором
Обновить

Комментарии 145

var Zoo = Zoo || {};
Красиво.
Если не секрет, то что это дает?
По сути, это определение JavaScript-объекта (то есть хэш-таблицы). Полями у него будут сами классы.
А дает это то же, что пространства имен в статическиях языках: имена классов должны быть уникальны только в пределах своего namespace.
Создать объект Zoo, если он ещё не существует.
Это очень распространнёная идиома на Javascript. Она почти во всём коде встречается :)
В JS операторы || и && работают несколько иначе, чем в C/C++ или Java. Они возвращают результат второго (а в общем случае — следующего) операнда:

Запись

var Zoo = Zoo || {};

эквивалентна

if (window.Zoo) { // в общем случае someScope.object
  Zoo = Zoo;
} else {
  Zoo = {};
}

Аналогично с &&:

someConditionTrue && doSomething();

что в развернутом виде с if'ами:

if (someConditionTrue) {
  doSomething();
}


В случае, если условия проверки единичны, то данные конструкции очень удобны (при условии, что скоп объекта однозначно заранее определен). В случае же с большим количеством условий, лучше воспользоваться if'ами — так код будет более удобочитаем.

.ps: аналогичная идеология используется в Python и Ruby.
Я в таких случаях предпочитаю использовать ?:
это нагляднее, неявного условия и короче громоздкого if else
> предпочитаю использовать ?:

дело привычки
В PHP похожие конструкции можно использовать, месяца 3 назад был пост на Хабре про такие финты на PHP. Используется принцип интерпретатора не разбирать дальнейшие условия в логической конструкции, если первая ложна.
Это Вы про $var = (condition)? ifTrue: ifFalse; или там есть еще что-то наподобие…? Кстати топик я пропустил, ссылочку не дадите?
У фреймворка kohana во всех файлах первой строчкой идет использование этой функции.
defined('SYSPATH') or die('No direct access allowed.');
Нашел – вот тут habrahabr.ru/blogs/php/38639/
Да, и Tagire ниже верно подметил, в PHP для таких манипуляций используется and и or.
А, этот пост. Да, читал, интересная статья…
не только and, можно и && =)

$array = array();

!$array && ($array = array(1, 2, 3));
Можно, только нужно аккуратно, т.к. у них приоритет исполнения выше, чем у следующих операторов:
= += -= *= /= .= %= &= |= ^= <<= >>=


поэтому, собственно, у вас инициализация массива взята в скобки =)
Ы )) минусанул новичок (и я знаю причину — эта запись с && несколько отличается от той, которую он видел в книжке «PHP для чайников» — и хрен ты бы с этим, да только я не пропагандировал, а показал возможность языка)

Благодарю.
в пхп true && '2' вернет true, так как перед интерпертацие выражения строка '2' приведется к булевому типу true.

в яваскрипте true && '2' вернет '2', а затем, если надо строка '2' будет приводиться к булевому 'true'
а && в PHP можно использовать для одиночных присвоений (кстати, удобно, когда надо что-то приплюсовать к элементу массива по одиночному условию), больше в этом ключе — не надо; в нотации из JS — в PHP это работать не будет
Честно-говоря, не пойму что тут красивого в половине, а то и в большей части существующих библиотек используются подобный прием.
JS очень красивый язык.
А вот эта штука как вам?

this[toggled == 'true'? 'show': 'hide']();

Хотя ее можно сделать более изящной.
Симпатично. Мне запомнилось ещё когдато промелькнувшее на хабре тестовое задани JS программисту: Написать функцию add(a)(b), ктоорая складывает два числа, и вызывается именно так.
Хм, интересно.
А есть решение?
да пожалуйста )
>>> add = function (a) { return function (b) { return a + b } }
function()
>>> add(2)(3)
5
вау, я и не знал что так можно.
Спасибо
function add(a) {
   return function(b) {
      return a + b;
   }
}
Каррированная функция, клево

Haskell в JS это завсегда круто :)
например так

this[toggled && 'show' || 'hide']();

:)))
Стоит понимать, что JS — сам по себе — уже очень объектно-ориентированный язык. Данная «обертка» (JsOOP) в любом случае не имитирует статическую классовую парадигму. Это всего лишь обертка для существующего в JS динамического ООП, основанного на делегации к прототипам. Никакое статическое ООП здесь сделать нельзя (это невозможно в текущей версии JS).

Все то же самое (организовывать порождающий объект («класс») для других объектов («инстансов»), организовывать наследование, вызвать родительские перегруженные методы из объектом-потомков) вы можете делать и без этого синтаксического сахара. Единственное, для чего можно применять данные обертки — это сокращение записи наследования (подмена дефолтного прототипа конструктора на wrapper, чей прототип ссылается на прототип родительского объекта). Все. И в этих обертках реализовано именно это. Ничего другого и «магического» (а уж тем более, статических классов из Си и Java, которые являются альтернативной ООП-парадигмой — не лучше-не хуже прототипной модели) там нет.
Ну и опять повторю — схожая идеологически модель, используется в Python и Ruby (только там это названо class) — вы не найдете и там статики, которую хотите сымитировать — объекты, классы (которые тоже объекты), их проперти, методы и т.д. — можно менять динамически в рантайме — так же как и в JS. Но — это уже названо class (сходство, естественно, не полное — процентов 80, но идеологически — в одну сторону смотрят). С таким подходом — можно идти в Python и Ruby и менять их организацию — вот только что-то останавливает — там, вроде как, уже есть слово class, да? :)
Абсолютно точно, изнутри это все то же динамическое ООП. Имитируется только синтаксис определения классов как в статической парадигме.
> Имитируется только синтаксис определения классов как в статической парадигме.

да не только как в статической, Руби с Питоном — динамические

Одна из основных идей статической модели — увеличение производительности за счет того, что не нужно каждый раз анализировать объект при обращении к его пропертям. Вместе с тем, статическая модель менее гибкая в организации. Поэтому, повторю — обе модели имеют свои плюсы и минусы. Не стоит смотреть на эти обертки, как на механизм, позволяющий «довести до ума» :) ООП-модель в JS. Смотрите на эту обертку — просто как на обертку. И всем передайте, что смотреть нужно именно так, тогда понимание различных парадигм (на «буквах», на «формулах», а не на «конкретных числах») придет очень быстро.
Попробую возразить. JavaScript версии
вот же :( комент скушался
JavaScript версии до 2.0 не является ООП по простой причине. Средствами языка невозможно реализовать три столпа ООП: наследование, полиморфизм и инкапсуляцию. Различные извращения не дают полноценного результата.
Далее, в версии 2.0 вводятся ключевые слова, которые позволят осуществлять ООП, но сейчас этого нет, потому не стоит искать то, чего нет. Ниже верно сказано «примите его таким, какой он есть».
> JavaScript версии до 2.0 не является ООП по простой причине.

Является. Конечно, является. Это ООП-язык с алтернативной (не дождетесь — я не устану повторять это слово и выделять его курсивом ;)) парадигмой.

ru.wikipedia.org/wiki/Прототипное_программирование

> Далее, в версии 2.0 вводятся ключевые слова, которые позволят осуществлять ООП, но сейчас этого нет, потому не стоит искать то, чего нет.

Да я и не ищу, я знаю, что оно есть. Я, в принципе, вообще не играю сейчас с Вами в игру «Кто интересней интуитивно догадается, что есть, а что нет в JS», я лишь рассуждаю относительно спецификации ECMAScript (абстрактно раздвигая ее рамки, проводя параллели с другими динамическими ООП-языками — Python и Ruby, где фигурирует понятие class).

По поводу 2.0. Давайте, тоже напишем небольшой пример, и посмотрим, что мы имеем в 2.0. (ES4) и 1.5 (1.6 / 1.7 / 1.8) (ES3). И как мы вынесем один повторяющийся кусок кода в функцию Inheritance.

> Ниже верно сказано «примите его таким, какой он есть».

Да я не сомневаюсь, что верно =) Я принял его таким, какой он есть, и вижу его на «буквах» (на «формулах»), а не на «числах».
и каким ты видишь «полноценный результат»?
Памятка для всех, кто часто использует слово из 3-х букв (ООП).

Javascript — это…

object-oriented
....object-based
........prototype-based
............delegation-based

… язык.
True :)
Не извращайтесь над JS, просто поймите его таким какой он есть
Ну тоже одну и ту же пластику не надо заводить постоянно. Ведь любая подобная тема содержит подобный Вашему комментарий. Причем, я склонен полагать, он появляется эфектом «взрывной волны», где «взрывом» являлось высказывание профи (при этом профи видет, как устроен JS и как устроенны другие языки, например Python и Ruby).

Поэтому, мне кажется, лучше подсказывать, помогать новичками понять суть и принципы (проводя параллели и аналогии), а не тыкать их, называя извращенцами.

А теперь вопрос лично к Вам — что Вы подразумеваете под «извращением» в данном случае?
typo:
эфектом -> *эффектом
Как согласный с автором комментария позволю себе ответить от себя — язык следует использовать так, как он создан, не надо языку с динамической типизацией и прототипами притягивать за уши парадигмы и приемы других языков. Недавнюю тему про аналоги функций php в js я считаю глубоко ошибочной — нельзя на одном языке программить по принципам абсолютно другого. Вы же не едите суп вилкой ;)
> язык следует использовать так, как он создан, не надо языку с динамической типизацией и прототипами притягивать за уши парадигмы и приемы других языков.

Вероятно (наиболее), что если человек говорит так, то он сам может не понимать, как работает OOP-модель в JS. Я не знаю, насколько это относится к Вам, буду верить, что в меньшей мере. Внутри обертки — используется именно это. Это лишь синтаксический сахар (не больше, ни меньше! вот — не больше! ни меньше!) для удобного описания наследования.

Скажите, как бы изменилось Ваше отношение к этому сахару, если бы главная оберточная функция была названа не Class, а, например, Inheritance? Или moyaUdobnayaObertkaDlyaPrototypnogoNasledovaniya?

Другой вопрос, что новичкам надо объяснять и показывать на примерах, что есть альтернативная ООП-модель и именно она используется в JS. И обязательно отметить, что смотреть на это все нужно только как на обертку — без изменения прототипной парадигмы.
Я прекрасно понимаю, что обертка — это именно обертка. Под последним предложением я вообще готов подписаться — как интересный прием эту обертку и следует рассматривать, а с точки зрения практического использования, я сильно сомневаюсь. Просто честно, не вижу смысла эмулировать какие-то вещи из других языков просто чтобы синтаксический сахар получить…
> а с точки зрения практического использования, я сильно сомневаюсь. Просто честно, не вижу смысла эмулировать какие-то вещи из других языков просто чтобы синтаксический сахар получить…

Хорошо, еще раз — давайте напишем тройной уровень наследования (и снова, забегая вперед, скажу, что там будет один повторяющийся кусок кода, и мы его вынесем в функцию и назовем ее Inheritance) и посмотрим, как этот код можно оптимизировать с точки зрения reusing'а.
JavaScript не объектно-ориентированный, а объектно-прототипный язык по своей сути, вы в курсе. И ООП (статическое), как раз является не оберткой, а эмуляцией. Ну или «эмулирующей оберткой» :)
Некоторые выражают недовольство, говоря, что JS не нужны классы в более классическом их понимании. Ну это уже дело вкуса и привычек восприятия. Кому-то это кажется синтаксическими сладостями, а кто-то именно за это цепляется и видит JS в свете «более ООП».
> JavaScript не объектно-ориентированный

Откройте стандарт, пункт 4 (самое начало), второй абзац:

ECMAScript is an object-oriented programming language

> И ООП (статическое), как раз является не оберткой, а эмуляцией.

Да нет здесь никакой эмуляции. Нет здесь никакой статики (и быть не может!). Обычная wrapper-функция-конструктор, которая делает удобным подмену прототипа на нужный.

> классы в более классическом их понимании

Все же, мне кажется, стоит говорить, «статические» классы. Потому что, опять, в Питоне и Руби — тоже классы, они также классические, но при этом — полностью динамические.

> Кому-то это кажется синтаксическими сладостями

Они не должны казаться таковыми. Они являются таковыми в единственно верном понимании (да простят меня все за такую формулировку и не сочтут за навязывание мысли).

> а кто-то именно за это цепляется и видит JS в свете «более ООП»

Так вот расскажите им (каждый раз, когда будете встречать), что это только лишь обертка, и что смотреть нужно (если они хотят понять JS) именно так, и что JS — изначально — ООП-язык и насквозь пронизан наследованием (как пример, можно попросить объяснить, что значит 1.toString();).

Аргументированно! Круто.
Но я, собственно, о том же самом говорил, только не до таких подробностей.

Вот замечание про «статические» и «классические» классы хорошее. Задумался :) И правда.

А про обертку я и имел в виду, что не столько обертка, сколько попытка эмуляции классов, в то время как в JS нет такого понятия «класс» как такового.
Язык без классов, но есть смесь (родитель+прототипы), никак не названная. Если бы назвали — было бы меньше аналогий.
» как работает OOP-модель в JS
Ну как она работает, я более менее знаю, уже не первый год с ним общаюсь… самый любимый язык, потому так ревностно и отношусь :)

P.S. а его синтаксис я вообще обожаю… за конструкции вида fncReturningArray(«id»)[0] в php бы душу продал… или за var Zoo = Zoo || {}; и вообще за JSON при описании PHP массивов, но это уже оффтоп.
> Ну как она работает, я более менее знаю, уже не первый год с ним общаюсь

ну, тогда и динамическую классовую модель в Руби и Питоном сразу поймете ;)
typo:
«не больше! ни меньше!» => ни… ни, конечно (тороплюсь просто)
Все дело в том, что статическая классовая парадигма для многих разработчиков (далеко не всех!) является стандартом при разработке сложных приложений.

В случае client-side разработки у нас, практически, нет выбора. Надо использовать JavaScript.
Разве что есть ещё Google GWT. GWT решают ту же задачу, но на другом уровне.
Про GWT процитирую коллегу: «не знаю, я не доверяю кодогенераторам, как потом дебажить, как контролировать кроссбраузерность». Гугл это круто конечно, но я предпочитаю не зависеть от сторонних библиотек… jQuery, например, использую только вследствие безумной удобности, а так — по минимуму стороннего, но без фанатизма «я все пишу только сам», иногда лучше всетаки довериться разработчикам, чем изобретать велосипед, но это опять же оффтоп.
> Все дело в том, что статическая классовая парадигма для многих разработчиков (далеко не всех!) является стандартом при разработке сложных приложений.

Вы это Руби- и Питон- программерам скажите (я имею в виду слово статическая)
Подписываюсь.
Зачем из прототипного языка делать непонятно что… Инструмент должен работать так, как задумано. К тому же мне кажется, что всякие такие обертки не будут ускорять работу скриптов ;).

Сугубо имхо: По мне так вообще прототипное программирование — вещь отличная, гибкая и удобная. Свобода действий… Обратная сторона — отсутствие строгости, но это преодолимо.
> Зачем из прототипного языка делать непонятно что…

Да тренируются люди, расслабьтесь Вы :) пишут просто удобные обертки — нет в этом ничего плохого, если они понимают суть вещей. Другой вопрос к Вам — что такое «непонятно что»?

> Инструмент должен работать так, как задумано.

Да он и работает так, как задумано (по-другому просто нельзя в данном случае реализовать)

> К тому же мне кажется, что всякие такие обертки не будут ускорять работу скриптов ;).

Производительность снижается за счет применения синтаксического сахара (часто — удобного).

» что такое «непонятно что»?
Я образно имел ввиду :) Имеем прототипный язык, код на котором будет построен на принципах статической модели, это и есть непонятно что :) я не знаю как это назвать… это два противоречащих друг другу принципа, просто гибкость динамической модели позволяет реализовать статику, наоборот-то будет гораздо проблемнее написать, если вообще возможно.

» Да он и работает так, как задумано (по-другому просто нельзя в данном случае реализовать)
Технически конечно работает, я про то, что прототипный язык должен работать как прототипный, без подобных граблей. Как эксперимент — зачет, но в проектах такое применять не следует…
«позволяет реализовать статику» — даже не реализовать, а «сделать вид, что это статика»
> я не знаю как это назвать…

Вот и я о том же. А дальше я попрошу взглянуть в сторону Ruby и Python'a — и найти 80%-сходство (при том, что названо это class).

> это два противоречащих друг другу принципа

противоречат только статика-динамика. Руби и Питон — динамические языки (с понятием class, очень схожим с ООП-моделью JS)

> Как эксперимент — зачет, но в проектах такое применять не следует…

да что жы Вы все эту шарманку крутите? ;) Хорошо. Давайте продемонстрируем тройной уровень наследования (я, заранее забегая, скажу — что там будет повторяющийся кусок кода, мы его вынесем (следуя code reuse) в функцию и назовем ее Inheritance).
Я потенциально не доверяю фреймворкам :))) вот когда будет немеряный стэйбл, тогда да, можно будет использовать. А пока это все-таки эксперимент… как дебажить мой скрипт, базированный на фреймворке версии 0.1 ;) я только об этом сейчас…
> Я потенциально не доверяю фреймворкам

да при чем здесь какие-то фреймворки? :) И вообще, что есть фреймворк? У меня, например, был свой фреймворк еще до того, как появились Prototype.js и jQuery. Я просто вынес удобные функции в одно место и юзал их.

Забудьте пока про слово «статика», просто посмотрите сходство (везде одна динамика, разная терминология, слегка отличающаяся идеология, в целом — 80%-сходство):

habrahabr.ru/blogs/javascript/40909/#comment_996830
habrahabr.ru/blogs/javascript/40909/#comment_997247
>Да тренируются люди, расслабьтесь Вы

Тренируются они на наших нервах. Программирование ради ре-юзинга. Уже и шагу нельзя ступить, чтобы не наткнуться на что-то громоздкое, еле работающее, чего-то там беспрерывно обсчитывающее и кого-то там постоянно наследующее… ради шевелящихся буковок или выпрыгивающих менюшек. Браузеры за «обёртками» не успевают увеличивать производительность. Скоро и железо отстанет. ;)
Привет, Zeroglif! ;)

Я вот когда говорил об эффекте «взрыва» и его «взрывной волне» как раз имел в виду высказывания вроде твоего. Несомненно, это правда, — особенно, касаемо тяжелых оберток или, когда имитируют функции, которые и так в JS есть (например, тема про имитацию функций из PHP). Но это может иметь и побочный эффект — тех же «чучел», — когда могут насмотреться на высказывание профи и потом неосознанно везде писать то же самое (при этом, как я часто замечаю, уровень знаний в JS несколько ниже, чем подается во фразе, услышанной у профи).

> Скоро и железо отстанет. ;)

Э-э, нет ;) Остановятся, если увидят, что «железо» еще не может развиться до определенной стадии (ну, не совсем уж дураки «там сидят»). Касаемо самого JS, — снова абстрактно — любая идеологическая конструкция в нем (хоть замыкания, хоть анонимные функции, хоть динамические объекты, хоть и т.д.) — есть (если очень абстрактно) также синтаксически удобный «сахар» (по отношению к языкам, которые не имеют таких возможностей и вынуждены писать кода в несколько раз больше). При этом, эти удобные обертки в любом случае понесли потери в ресурсах — статические классы быстрее динамических.
Я не знаю, чего тебя пугают «побочные эффекты» эти, всё равно потонут они. Ну, будет десять человек вроде меня вякать против тренда, и чего? Ничего.
Да не пугают они меня вовсе, я знаю, что на них отвечать, а если не знаю — ищу знаний. Насчет мэйнстримовых трендов — если институты слишком большие (типа jQuery) — да, ну уровне локальных высказываний на форумах, мало что решается (хотя… почему нет?). В целом же — эти «десять человек» в любом случае помогают, показывают, что стоит за «всем этим».

Касательно самого понятия тренд — а что, сам JS не был трендом в свое время (да и сейчас тоже)? Тут главное — позиция: «объект тренд — поэтому он крут», «либо объект — крут, поэтому — он тренд».
> мэйнстримовых трендов

опять масло масляное получается вроде =) а может быть и нет
пачиму нет множественного наследования?
расскажу вам, пожалуй, одну страшную, но правдоподобную историю…

однажды, в чёрном-чёрном лесу, в черном-чёрном интернете сидел бледный-бледный программист. И довелось ему в эту самую ночь копаться с чужим яваскриптовым апи, выполненным в лучших традициях какбы-ооп из дважды плюсанутого си.

так вот, потребовалось ему сохранять некое состояние объекта между сессиями. а состояние этим апи выдавалось… нет, не строкой, а статической константой. устанавливалось оно тоже только этой самой константой. вот только беда — между сессиями нужно было сохранять имя этой константы, а в самой константе, разумеется, её имя написано небыло ( это же константа! — видимо, думал автор, — просто пишем в коде её имя! ).

в результате всего этого пришлось для сериализации какой-то паршивой константы городить громоздкий свич. и если бы это давало +2 к наглядности или хотябы +1 к скорости… но нет, этот мусор из статических языков только замедляет и усложняет код.
Да и… Рассуждая о понятии класс, я не призываю к оберткам, я как раз отметил, что все это вы можете делать и без оберток. Я лишь хочу, чтобы люди (и те, которые пишут новые обертки, и те, которые не ленятся каждый раз писать «извращенцы») услышали слово «альтернативный» (ООП-подход) и не несли в общество безграмотность, выставляя классовый подход «пуголом» или же не понимая прототипного подхода.
Таким же методом организовано ООП в JS фреймворке QooXdoo. Прошлый проект писал на этом фреймворке. Интересно кто с кого списал)
Стоит оговориться, что поддержки полноценных закрытых и защищенных (private и protected) полей и методов класса в JsOOP нет. Поэтому вводится рекомендация начинать имена таких переменных и функций со знака подчеркивания.

Это не тру подход, я предпочитаю все же создавать настоящие private переменные.
Я вообще не понимаю зачем делать из JS ООП? Существует огромное количество других парадигм и Прототип-ориентированные ЯП тоже очень классные. Я думаю пробелам в том, что в школах/институтах учат в основном только языкам одной группы — ООП по C++. Ведь даже ООП в оригинале был совсем другим — посмотрите Smalltalk, Ruby.
>>Я вообще не понимаю зачем делать из JS ООП?

Вы немного запутались в терминах. JS — обьектно-ориентированный язык программирования, наследование в котором реализовано с промощью прототипирования.
Вообще очень спорно. ООП всё таки предполагает наличие класса и правильнее, наверное, разграничить ООП и ПОП, хотя они конечно роднее, чем процедурный или функциональный стили. В англоязычной Википедии говориться, что «Multi-paradigm: prototype-based, functional, imperative, scripting». Хотя ребята из Mozilla пишут только «object-oriented».

Поэтому уточнюсь: в данном комментарии под ООП я имел в виду принципы ООП из C++/Java/C#. Как минимум ООП в Smalltalk/Ruby совсем другой.
Для разъяснения подобных вопросов лучше сразу смотреть в спецификацию.
Терминология, терминология… Комментарий выше — вот как целиком называется :)
>Прототип-ориентированные ЯП тоже очень классные

Точно. Очень классные, но без классов. ;)
Иногда это крайне удобно… Допустим я создаю сразу объект, выполняющий нечто. Без классов, без ничего… просто пишу

var myObj = {
a = function() {},
b = function() {},
str = "",
}

и сразу пользуюсь

myObj.a();

В случае PHP для такого дела надо было бы использовать статические функции и переменные, а уже совсем не ООП, когда класс сам по себе является подобием объекта. Так что оба подхода полезны и важны, надо использовать сильные стороны языка, тогда все будет ок )
ага, похапэшники, когда слышат «локальный синглетон» недоумевающе разевают рты ;-)
Не-а :) Про синглетон знаю, пользовал, хороший паттерн, но… Синглетон — это еще некоторое количество кода :) а я имел ввиду краткость кода
чтд.
Вы же синглтон то как-то описывать в коде будете, правильно ;) Несколько строк понадобится, а тут бери да пользуй.

Насчет локального синглтона… погуглил, нашел статью про потоко-локальный синглтон и вот эту статью.
нет, я к тому, что тот код, что ты написал — это самый что ни на есть «локально определённый единичный объект».
Семен семеныч :) Терминология… Кстати если то же самое написать непосредственно в теге скрипт, вне функций и т.д., то получившийся объект будет доступен глобально, даже «var» можно не писать. Единичность от места не изменится, есессно…
Я под синглтоном привык понимать класс со статичным методом аля getInstance… ну там sql::getInstance()->query();, который при создании нового объекта, если объект уже создавался, просто вернет ссылку… Запутал ты меня )))
угу, ибо в классово ориенторованных языках по другому нельзя. хочешь получить объект — изволь создать класс и попросить его создать объект.
> ибо в классово ориенторованных языках по другому нельзя. хочешь получить объект — изволь создать класс и попросить его создать объект.

.python:

my_obj = {
  'a': 10,
  'test': lambda x: x + 10,
  'b': 20
}

my_obj['a'] # 10
my_obj['test'](10) # 20
my_obj['b'] # 20
питон — не классово ориенторованный, если ты об этом

> питон — не классово ориенторованный

ну, кардинально отходить от терминологии с элементами отсебятины, — я так не смогу рассуждать ;)

В Питоне — существует понятие «Динамический класс, порождающий инстансы», инстансы делегируют к классу (подобно в JS к прототипу конструктора), за исключением некоторых особенностей.
классово ориентированный — язык в котором для порождения инстансов требуется создание класса.
если этого не требуется, то перед нами объектно ориентированный язык. существование объектов-фабрик под кодовым именем «класс» не делает язык ориентированным на классы, а лишь предоставляет возможность их использования.
твоя личная формулировка, словесная эквилибристика (которой все, что хочешь можно доказать) =) не будем в этом ключе — все равно толку нет.

Можно другую формулировку — классовый язык — такой язык, в котором существует понятие «класс» — не важно — динамический, статический, выступающий фабрикой, заводом и т.д.
в любом языке можно ввести понятие «класс». яваскрипт, как видим, не исключение.

разница лишь в том, что в одних языках без классов и шагу не ступить, а в других — как-то и без них справляются.
ну, если абстрактно, — то да
Упс, нашел опечатку… вместо знаков «=» конечно же должно быть «:»
Здесь dean.edwards.name/weblog/2006/03/base/ также можно найти простую и небольшую обертку с аналогичной функциональностью.
наиболее изящно (не знаю даже, куда уж изящнее) в этом плане сделан mootools, и в данном случае нет смысла делать такой мини-велосипед, кроме как в образовательных целях, но тут это не раскрыто…

и насчет холиваров class vs. prototype: вообще, порядком надоело уже это. почему-то никто не может толком объяснить, чем же так хорош prototype-подход, какие он дает конкретные преимущества. почему то не было ни одного развернутого поста с примерами на эту тему, все только язвят в стиле «не надо насиловать язык», при том что язык этот не диктует строгую парадигму. напишите статейку или киньте что почитать, господа, а то возникает мысль, что все только прикручивают аякс и эффектики с jquery, для чего особого подхода к пограммированию то и не требуется.
> и насчет холиваров class vs. prototype

а, кстати, — в этом топике холивора не было ))

И я предлагаю, когда кто-то захочет сказать «нах классы», говорить: «я вот только знаю статические классы и чуть-чуть слышал о прототипах в JS. Но я хочу заявить — не надо извращаться над JS, примите его таким, какой он есть (да, и… если честно, — это не моя фраза, я ее слышал у одного профи)». Вот тогда будет честно и справедливо! (никого не обижаю — в шутку это все говорю)

> чем же так хорош prototype-подход, какие он дает конкретные преимущества

Основное преимущество — это расшаривание свойств между всеми порожденными объектами. Таким образом, потребляется меньше памяти. Обращение к этим расшаренным свойствам (чаще всего — это методы) происходит посредством делегирования к прототипу конструктора (именно там они хранятся). Главная суть — если свойство не найден в самом объекте, его поиск продолжается в цепи прототипов. Эта цепь и образует наследование.
Поправлюсь про «высказывания» — естественно, нет ничего плохого, чтобы принять позицию высказывания профи, и потом использовать эти слова (поскольку, если человек профи — его слова в 97-100% истинны относительно того, о чем он рассуждает; как говорил кто-то там (не помню) — «все, что сказано красиво (а в данном случае, грамотно), я считаю своим»). Я лишь к тому, что надо быть всегда готовым поддержать свои слова и, в случае утверждений, обязательно иметь четкое представление о предмете.
Простота, динамика, мир объектов, а не абстракций.
разве объект это не абстракция над все теми же пресловутыми переменными и функциями? обертка — свойства и методы для работы с ними, с целью инкапсуляции

я понимаю, что это полная свобода, но дает ли она простоту в конечном счете? на ум почему приходит: это собака, она — самостоятельный объект, ей можно приделать рога. а зачем?
постмодернизм, пардон. никакой иерархии, а что в итоге?
Хорошо. Заменяю на мир более простых и понятных абстракций.
афайк в КОП то же самое. просто все экземпляры делегируют к своему классу, тот — к суперклассу и тп.
единственное отличие КОП от ПОП — экземпляр может содержать методы, не унаследованные ни от кого.

вариант «отнаследуемся от другого рабочего экземпляра» я разумеется не рассматриваю, ибо глупость несусветная.
зависит от реализаций, я полагаю; вот, к примеру, из ES4 код ниже — здесь не делегация, каждый инстанс имеет свой метод «test» (я не знаю, как это реализовано на уровне движка, может делается какая оптимизация и это, на самом деле, один метод, но тем не менее, в JS — у каждого объекта — свой одинаковый по семантике метод)
дык классы там небось разворачиваются во что-то вроде:

function A {
this.test= function(){}
}

вот попробуй создать два класса от одного суперкласса, в котором определён метод. и сравнить методы подклассов…
нет, это ничего не даст.

нужно создать класс, который унаследует от суперласса метод. а потом сравнить методы двух экземпляров.
да то же самое будет =) там специальная фишка есть — все так же можно в прототип выносить:

dynamic class A {
  function test() {}
  prototype function test2() {}
}

var a = new A();
var b = new A();

print a.test === b.test; // false
print a.test2 === b.test2; // true


Хотя, какая разница, все равно ES4 не прижился.
с этим-то понятно. вопрос в том, будут ли методы всё-ещё неравны после наследования…
В смысле — проверить, что

B.method === A.method, где A — базовый класс, а B — наследник? Я не знаю, как достучаться до такой конструкции (через класс, в смысле — скачай ES4 — посмотри, я его внутренности не знаю)

Порожденные же инстансы, будут выдавать false на ===, если метод описан в прототип — true =) Вот тоже — что это за смесь такая (идиотская, а может и нет) — класс ввели — но тут же рядом — прототипы =)
нет, я про случай, когда метод определён в А, от которого отнаследован В, от которого отинстанцированны 2 экземпляра. будут ли у экземпляров методы равны?
неа:

dynamic class A {
  function test1() {}
  prototype function test2() {}
}
dynamic class B extends A {
  function test3() {}
  prototype function test4() {}
}

var a = new B();
var b = new B();

a.test1 === b.test1 // false
b.test2 === b.test2 //true
a.test3 === b.test3 // false
a.test4 === b.test4 // true
значит всё ещё печальней — метод test1 создаётся заново при каждом инстанцировании…

а можно ли сделать обычный метод прототипным при создании класс наследника?
Тоже нет, — если объявлен метод в предке, то объявление прототипного метода с таким же именем в потомке — ничего не даст (будет использован метод из предка, поскольку это this-свойство и оно найдется сразу).

The . operator produces a function (more specifically, a closure) that is already dispatched and has this bound to the left operand of the. operator.

docs.huihoo.com/web/js/es4/core/classes.html
ужос… не удивительно, что инициатива заглохла ;-)
Ага =) это вообще, дикая смесь какая-то. Я бегло тогда читал overview-es4, — с виду показалось перегруженным, лишние конструкции. Написано, что все еще так же можно использовать function A() {} и ее прототип для порождения инстансов (как альтернатива class A).
>Таким образом, потребляется меньше памяти.
хорошо, но есть какие-то исследования, замеры? заметен ли выигрыш по ресурсам?
самые большие проблемы с памятью возникают из-за утечек, которые не связаны с подходом… скорость выполнения вещей типа перебора элементов или каких-то вычислений — тоже
что ощутимо дают прототипы? есть ли какие-то серьезные проекты или исследования, где использование этого подхода дало оптимизацию ресурсов/архитектуры/скорости разработки/более понятный код или еще что-либо?

вот, например, я смотрю на код, который вы написали ниже, и мне кажется (может я и ошибаюсь конечно), что он многословный, неинтуитивный. ну не вижу я преимуществ (

вот пример из мануала мутулз:

var Animal = new Class({
initialize: function(age){
this.age = age;
}
});
var Cat = new Class({
Extends: Animal,
initialize: function(name, age){
this.parent(age); //will call initalize of Animal
this.name = name;
}
});
var myCat = new Cat('Micia', 20);
alert(myCat.name); //Alerts 'Micia'.
alert(myCat.age); //Alerts 20.

если его переписать под чистый незамутненный prototype-based, он станет лучше?
если это слишком типичный пример, есть ли пример, который продемонстрирует очевидные реальные преимущества прототипов?
> хорошо, но есть какие-то исследования, замеры? заметен ли выигрыш по ресурсам?

Однозначно, — делегирующая модель жрет памяти в n-раз меньше, относительно каскадной модели. Однако, не во всех классовых организациях, я полагаю, используется каскадная модель — см. пример из ES4 выше, когда у каждого из инстансов появился свой метод «test». А если инстансов будет 10000? Есть разница? 10000 объектов или один? Но и тут, я склонен полагать, что какая-то оптимизация используется.

В свою очередь делегирующая модель медленней — поскольку нужно просмотреть всю цепь прототипов, если искомая проперть окажется на самой «глубине».

> вот, например, я смотрю на код, который вы написали ниже, и мне кажется (может я и ошибаюсь конечно), что он многословный, неинтуитивный. ну не вижу я преимуществ

Ну это организация наследования без оберток. Вам значит удобней использовать обертку. Просто имейте в виду (нет, — знайте!), что внутри обертки mootools'a — то же самое.

> если его переписать под чистый незамутненный prototype-based, он станет лучше?

относительно ресурсов — станет быстрей, относительно удобочитаемости — каждый сам решает, в целом — лучше-не лучше — а то же самое.
> Однако, не во всех классовых организациях, я полагаю, используется каскадная модель — см. пример из ES4 выше

путанная фраза получилась, я имею в виду, что в ES4 в данном случае как раз-таки получается (с виду, я не в курсе оптимизаций внутри движка и спецификацию ES4 не читал) каскадная модель
=) да я понимаю, что обертка.

я говорю не только о внутренней организации, но и о вещах, которые важны для языка как инструмента, а не только как теории

мне интересны жизненные примеры, которые показывали бы, в чем prototype-стиль оказывается дает ощутимые преимущества относительно class-стиля.
меня интересуют причины, по которым стоит отказаться от более строгого, более классического подхода.

немного выше Zeroglif писал, что сама концепция проще. ну да, согласен, но при этом код проще ну никак не выглядит. сейчас вот подумал, что это, наверно, недостаток именно ES как реализации идеи…
> но и о вещах, которые важны для языка как инструмента

какие конкретно вещи интересуют?

— инкапусляция? — строгой нет, и быть не может (var'ы тоже хаком можно достать, если потребуется)

— наследование? — изначально заложено в JS (еще можно ни одной серьезной строчки кода не написать, а наследование уже во всю работает — 1.toString() — как Вы объясните это поведение? Что здесь происходит?)

— полиморфизм? — можно перегружать методы (поиск в цепи прототипов остановится на первом найденном методе), можно вызвать одноименные родительские, если сделать ссылку на родительский конструктор (или его прототип — как удобней)

— можно динамически менять предков — меняя прототип (подобного эффекта можно также добиться агрегацией)

> в чем prototype-стиль оказывается дает ощутимые преимущества относительно class-стиля.

динамика, делегирование, расшаривание одних сущностей между порожденными объектами

Статические классы — быстрее, менее ресурсоемки, но, вместе с тем, — менее гибки.

> немного выше Zeroglif писал, что сама концепция проще. ну да, согласен,

а где именно Вы согласны? Zeroglif за себя говорил, а что Вам показалось проще?

> но при этом код проще ну никак не выглядит.

да какие проблемы? опишите функцию, добавьте методы в прототип:

function MyClass() {}

что-то странное — какие-то клавиши моментом отправляют коммент. Не дописал:

function MyClass() {}

MyClass.prototype = {
method1: function () {},
method2: function () {},
и т.д.: что-то там
};

var a = new MyClass();
a.method1();
a.method2();
> какие конкретно вещи интересуют?
скорость разработки, лаконичность и «человечность» кода, легкость поддержки.
мне очень нравится питон, например. предлагая большую гибкость, он одновременно предлагает изящную форму и неплохое отношение к ресурсам.

я не вижу, с какой целью можно еще дальше сдвигать парадигму
> что Вам показалось проще?
идея того, что любой объект автономен и полностью изменяем. эта идея сама по себе очень проста.
однако, опять же, мне видится это overkill'ом из-за слишком большой свободы.

>какие-то клавиши моментом отправляют коммент
ctrl+enter? )
> скорость разработки, лаконичность и «человечность» кода, легкость поддержки.

все это пытаются делать в обертках (типа jQuery, Prototype и т.д.), естественно, жертвуя производительностью в ресурсах

> скорость разработки, лаконичность и «человечность» кода, легкость поддержки.

а можно и без фреймворков (насчет последних трех пунктов — точно), а вот насчет скорости разработки — смотря, что разрабатывается

> мне очень нравится питон

ну и JS, значит, тоже должен ;) поскольку, идеи общие

> идея того, что любой объект автономен и полностью изменяем. эта идея сама по себе очень проста.
однако, опять же, мне видится это overkill'ом из-за слишком большой свободы.

так в Python'e тоже самое (все объекты динамические и автономные):

class A(object):
  def __init__(self, a=10):
    self.a = a

  def test(self):
    print self.a

a = A(20)

a.a # 20
del a.a
a.a # None
a.a = 10
a.test() #10
a.b = 20 #20 (собственное свойство)

b = A()
b.a #10 (по умолчанию из конструктора)

a.__class__.c = 30 # расширили класс новым свойство

a.c # 30 оно доступно (посредством делегирования) во всех порожденных инстансах
b.c # тоже 30

a.c = 40 # перезаписали, свойство "с" теперь свое

a.c # 40
b.c # 30 - делегация

del a.c

a.c # 30 снова делегация

del A # удаляем ссылку на объект-класс

b.__class__.d = 50 # но все еще можем расширять объект-класс через инстансы

a.d # 50
b.d # 50
> так в Python'e тоже самое
так питон-то «нативно» поддерживает классы, без оберток )

вобщем, ладно, все, а то что-то не в то русло пошло ))
спасибо за интересную дискуссию =)

возможно я слишком привык к классам, нужен какой-то перелом в мышлении…
но все же очень хотелось бы посмотреть более-менее сложный проект с серьезным применением прототипов без костылей
> так питон-то «нативно» поддерживает классы, без оберток )

=) замените слово «class» из Питона на «function» в JS — практически не найдете отличий

> но все же очень хотелось бы посмотреть более-менее сложный проект с серьезным применением прототипов без костылей

можно порыться в .js-файлах firefox'a или thunderbird'a, которые с XUL'ом и XPConnect'ом общаются (там, конечно, тоже не прелесть, но — как пример — можете посмотреть, как там используются прототипы)

> вобщем, ладно, все, а то что-то не в то русло пошло ))
спасибо за интересную дискуссию =)

о, пардон, если показался слишком навязчивым =) и Вам спасибо )
нет-нет, это я скорее упертый ) а вашему энтузиазму на разъяснения можно позавидовать ))
сохранять это все надо бы куда-нить, а то ведь утонет же тут…
Вот еще кодом можно показать:

Код из ES4:

dynamic class A {
  function test() {}
}

var a = new A();
var b = new B();

a.test();
b.test();

a.test === b.test // false

a.hasOwnProperty('test'); // true
b.hasOwnProperty('test'); // true

// наследование - как в Java

class B extends A {} // и т.д.


На этом этапе все полностью то же самое, можно сделать в ES3 посредством функции-конструктора:

function A() {
  this.test = function () {};
}

// дальше тоже самое


А теперь с хранением свойства «test» в прототипе конструктора:

function A() {}

A.prototype.test = function() {};

var a = new A();
var b = new A();

print a.test === b.test; // true

// наследование

function B() {
this.b = 20;
B.superсlass.call(this, arguments);
}

var __inheritance = function() {};
__inheritance.prototype = A.prototype;
B.prototype = new __inheritance();
B.prototype.constructor = B;
B.superсlass = A; // явная ссылка на «А» для вызова родительских методов
кстати, а ты что думаешь об этом: groups.google.com/group/jfix-javascript-framework/browse_thread/thread/2bfec344ca3c1106?
своеобразная обертка, вероятно, — тебе удобная (иначе бы ты ее не писал); anyway, внутри — суть та же.
нет, это не обёртка, это — raw-javascript B-)
а, ну да, сверху нет функции с пугающим словом «класс» ;) интересно, мне нравится
Мне больше нравится использовать Javascript таким, какой он есть. Это интересно и полезно для общего развития :)
чем таким особенным конструктор отличается от остальных методов, что его потребовалось выделять в отдельное поле?
может не втом топике задаю вопрос, НО:
Зачем нужны классы, Особенно в javascript? Чем не хватает функций.

Кто-нибудь может привести в пример задачу которую невозможно решить без классов(на скриптовых языках)? Они ведь придуманы наверняка не просто потому что красивее с ними.

Часто читаю чужой код, где в рабочем скрипте кроме классов и их методов практически ничего нет, т.е. — есть куча операция с непонятными названиями(чаще всего), мануала конечно же нет и вместо того чтобы разработчику сходу прочитать код, приходится лезть, открывать кучу файлов и разбираться зачем какой класс нужен. Чтобы полноценно работать с проектом нужно практически выучить новый синтаксис этих классов, их названия и методы. Что же хорошего в такой абстракции?

предполагаю, что вопрос многим покажется глупым, у меня всегда были проблемы с пониманием именно самых фундаментальных вещей…
так что аргументируйте минус который мне поставили :)
> Что же хорошего в такой абстракции?

А ничего. Это просто некоторые особо ленивые хотят, чтобы JS стал то недоПедоном, то почтиРуби, а то и вообще типаХацкелем.
> особо ленивые хотят, чтобы JS стал то недоПедоном, то почтиРуби

С этого места поподробней (про ленивых), пожалуйста. Насколько глубоко Вы знаете JS?
> С этого места поподробней (про ленивых), пожалуйста.

Я кого-то задел? Лень это круто ведь. Двигатель прогресса.

Если Вас спасают классы и наследование — пользуйтесь на здоровье.

> Насколько глубоко Вы знаете JS?

Пейшу и четаю (и то, и другое не люблю делать). А scoping rules в JS реально очень замудренные, примеры можете не приводить.
> Лень это круто ведь. Двигатель прогресса.

Двигатель прогресса — это мысли идеологов, это идеи созидателей. При этом ими движет — нет, не лень (простите, это — чушь), ими движет желание увидеть, что будет дальше. Они осознают, что, если будут использовать текущую абстракцию — могут не успеть, поэтому садятся, и пишут еще более совершенную. Далее, тратят меньше времени.

Потребители же, — могут говорить — «лень — двигатель прогресса» (при этом, не являясь создателями этих «благ»). Да-да, это им (потребителям) принадлежат фразы типа «зачем создавать велосипед, когда можно пользоваться готовым?». Кстати, в этом нет ничего плохо — потребители дальше сами становятся созидателями и идеологами. Вот здесь чуть-чуть излагал эту мысль. (PS: это лишь мое видение)

> Если Вас спасают классы и наследование — пользуйтесь на здоровье.

Я больше теоретик (идеолог), и больше изучаю, чем использую. Любая абстрактная вещь — мне интересна, я ее мало конкретизирую.
> Они осознают, что, если будут использовать текущую абстракцию — могут не успеть, поэтому садятся, и пишут еще более совершенную.

Что-то не вижу бенефитов от приделывания Simula-style OOP к JS. Ну в упор не разгляжу что-то. Функции — наше все.

> Я больше теоретик (идеолог), и больше изучаю, чем использую

Поизучайте монады тогда, что ли =) (Они правда несложные, токо само понятие очень абстрактное, да)
> Что-то не вижу бенефитов от приделывания Simula-style OOP к JS. Ну в упор не разгляжу что-то.

а где Вы вообще увидели Симула-стайл? Я как раз на протяжении всех комментов, говорю, что все это можно делать без оберток, и говорю, что внутри оберток — все те же прототипы.
It quacks like a duck, so it's a duck.

Как оно там внутре реализовано, значения не имеет.
> Как оно там внутре реализовано, значения не имеет.

что значит, не имеет? именно это и имеет значение, раз речь идет о прототипном языке. Моя главная мысль, чтобы новички — смотрели на обертки, как на обертки (ни больше, ни меньше) и одновременно с этим не думали, про классовое ООП, как о «пугале».
> что значит, не имеет?

То и значит, извиняюсь за грубость. =) Абстракцыя это. У абстракцыи главное что? Главное — не смотреть унутрь, на детали!
> У абстракцыи главное что? Главное — не смотреть унутрь, на детали!

Балин =) Это верно! (вот как поспорить с такой фразой? Особенно, если абстракция уже не ближней стадии, а в пятом поколении. — Только разработчики смотрят внутрь движка JS, пользователи JS — лишь немногие). Но — не запрещено смотреть, особенно, если интересует суть ;)
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории