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

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

Почему вы такой злой? «Безвестными мудаками...» Интересно, к кому вы себя относите…
НЛО прилетело и опубликовало эту надпись здесь
Я не злой, я описываю то, что вижу.

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

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

Себя я отношу к промежуточному варианту — я не пишу всякой фигни, но и не маститый метр.
Лучше учить неграмотных, нежели обвинять некомпетентных.
Я и не обвиняю, я просто констатирую факт. Впрочем, я согласен, что в данном случае посыл о безграмотных разработчиках-мудаках был лишним. Пожалуй, я его уберу, раз уж это отвлекает людей от собственно содержания и главной мысли статьи.

Здесь же, в этой статье, я в меру своих знаний стараюсь показать, как написать безопасный, багоустойчивый, быстрый, легковстраиваемый и масштабируемый виджет.
Те «беззвестные мудаки» в рамках своих знаний тоже пишут безопасные, благоустойчивые… и т.д. виджеты. :)
Модель ExtJS работает по такому же принципу, на сколько я понимаю.
Все хорошие библиотеки используют такие или схожие принципы.
НЛО прилетело и опубликовало эту надпись здесь
Да, моя любимая javascript-библиотека, так сказать, framework of choice, YUI.

И значительную часть своих знаний о javascript я получил, копаясь в ее исходниках.

Тем не менее, части скрипта (обработчики событий, purge и setInnerHTML), архитектурные принципы (модульный паттерн, а также один глобальный объект — ну это-то вообще седая древность) используются вовсе не только в YUI, но и в других фреймворках.
НЛО прилетело и опубликовало эту надпись здесь
Мне все же кажется, что вы перегибаете палку.

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

Я все же настаиваю на том, что ни одна часть кода, приведенного здесь, не принадлежит только YUI (в том смысле, что сходные подходы используются и в других фреймворках).

Тем не менее, это не YUI и не урезанный YUI, хотя вам, как человеку, много работающему с YUI, так кажется.
Хотя, с другой стороны, возможно, вы и правы — возможно, я, сам того не сознавая, один в один повторяю YUI, просто потому, что считаю, что писать так — правильно :)
НЛО прилетело и опубликовало эту надпись здесь
Если в качестве обработчика нажатия на кнопку хочется навесить вызов метода объекта, то как вы поступаете?
Там в конце, где указаны пути улучшения виджета, указано, что нужно передавать в callback еще и контекст исполнения, тогда можно будет и метод объекта безопасно вызывать.
проиллюстрирую:
в параметр callback (в том случае, если он — объект) добавляется новое поле, к примеру, context.
и тогда, если он присутствует, что функция обработчик навешивается таким образом:

DEMO.DOM.addListener(button.id, button.callback.type, function () { 
    button.callback.fn.call(button.callback.context);
});


И в таком случае мы сможем передавать методы объекта в callback таким способом:

callback : {
    type : 'click',
    fn : method,
    context : obj
}
Забыл добавить — таким же способом можно и данные передать в метод/функцию callback.
Угу, понял метод. Можно еще кроме контекста добавить и аргументы.
Собственно что и было сказано комментарием выше :)
Вы тоже думаете, что возможность редактировать комментарии на хабре не помешала бы? :)
и еще, чтобы комментарий прочитывался голосом, прежде чем его добавить :)))
Тоже неплохо было бы :)
И еще. Вы думаете, данный виджет не обладает утечками памяти?
Думаю, да. Впрочем, если я что-то упустил, буду признателен, если вы укажете на мою ошибку.

Я думаю, что можно выкинуть purge и setInnerHTML, а просто кешировать старый объект o.buttons, и перед hide/render пробегаться по этому массиву, снимая обработчики с помощью removeListener.

Тогда можно воспользоваться просто свойством innerHTML private-свойства dialog объекта DEMO.Dialog и не париться с удалением цикличных ссылок.

Других обработчиков я не навешиваю, все переменные у меня внутренние, а объект div.dialog как появился, так потом только прячется, и удалить ссылки на него из javascript — дело того, кто будет (если будет) удалять этот div.
Точно будет утекать в IE приватный dialog (DIV), ссылку на который обнулить может только ваш виджет, но соответствующего метода для этого не предусмотрено. Кроме того, тут нужна функция на unload документа, которая и будет вызывать метод виджета для обнуления ссылок и отвешивания событий.

Не уверен — надо разбираться, но скорее всего будут утекать замыкания с передачей им DOM-объектов — например при желании на onclick кнопки сразу вызвать какой-то их метод:
— callback: {
type: 'click',
fn: 'focus',
context: document.getElementById('inputTextEnterPassword')
}
— Вообще разработчики браузера сделали медвежью услугу программистам, создав автоматический сборщик мусора, который не может собрать весь мусор. И потому следить за всеми ссылками, событиями, замыканиями — это головная боль разработчика на Javascript. Забить на которую к тому же подталкивают
— отсутствие инструментов для наблюдения за внутренностью js-движка (drip инструментом не считаю, это лишь слабейший сигнализатор)
— отличие менеджеров памяти в разных браузерах (в этом глюки есть, а в том — нет)
— предполагаемая недолговечность жизни открытых веб-страниц, ведь в 95% случаев юзер закроет это окно браузера в течение 5-10 минут и вся память автоматически высвободится уже на уровне ОС

Да, вы абсолютно правы.
Вечерком доработаю скрипт.
Огромное спасибо за уточнение — второго пути утечки я даже не увидел :)

Ну и насчет ограничений браузеров я также полностью согласен — скольких бы бессонных ночей не было бы, если бы был хотя бы инструмент, которым можно посмотреть, что там происходит в js-engine.
Об этом и пойдет речь в сегодняшнем посте — как сделать простейшее диалоговое окно и alert средствами чистого javascript, без применения каких-либо фреймворков.

Пользоватся фреймворками не зная как это сделать чистым яваскриптом — плохая идея. Очень плохая и ни к чему хорошему не ведущая.
Полностью согласен, это одна из причин появления этого поста.
Т. е. были прецеденты? Печально, если так.
Интересно было почитать, спасибо.
JavaScript: The World's Most Misunderstood Programming Language, к сожалению.

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

Приятно слышать похвалу :)
Крокфорд, кстати, далеко не идеал и временами ошибается, причем в важных местах. И его инструменты и предложенные скрипты содержат ошибки.

Из запомнившегося — попробуйте, например, с помощью его подхода добавить сделать иерархию наследования class1->class2->class3->class4->class5.., в которой class1, class3, class5… имеют метод, который возвращает название текущего класса и вызывает такой же родительский метод. В результатет выйдет вовсе не желаемое '...class5 class3 class1', а нелогичное 'class5 class3 class3 class1' (результат сказал навскидку, примерно такой он будет). Вопреки его потугам, JS таки не может автоматически наследовать с перегрузкой методы родительского класса и анонимно их вызывать.

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

теорию надо глубже изучать ;)

> эта его нелогичность меня еще больше к нему влечет :)

логичный он, логичный.
А может мы не будем цепляться к каждому слову?

Или мне начать перечислять оглавление «bad parts» из книги Javascript: The Goods Parts?
> А может мы не будем цепляться к каждому слову?

Если Вы думаете, что это моя самоцель, то, уверяю Вас, — это не так. Делать мне больше нечего =) С другой стороны, — как же не отметить, что — «здесь и здесь Вы не точны»? Иначе, Вы будете нести безграмотность в массы.

> Или мне начать перечислять оглавление «bad parts» из книги Javascript: The Goods Parts?

Читал. Там высказаны личные мысли Крокфорда (со многими из них можно согласиться) по поводу того, чего бы хотелось в JS видеть (и чего там в текущей реализации нет); ничего там про то, какой JS «ужасно разболтанный язык и поддается нормальному описанию в рамках ООП» нет. К тому же, мысли эти где-то могут быть спорными.

Ладно, флудить, действительно, не будем; топик, как-никак, про виджеты.
> Но JS — ужасно разболтанный язык, и… все-таки не поддается нормальному описанию в рамках ООП.

тоже теорию надо глубже изучать, чтобы не писать о «рамках ООП»
поясните
> поясните

с удовольствием, если Вы просветите меня о «рамках ООП», в которые JS не вписывается, и посему становится разболтанным.
То есть, вы пишете ответ на комментарий, смысл которого не понимаете?

Чтобы не делать copypaste-текст-reuse, я сделаю линк — см выше и читайте комментарий снова. Там все сказано.

> То есть, вы пишете ответ на комментарий, смысл которого не понимаете?

Демагогия.

> Там все сказано.

А причем тут Крокфорд и его реализация чего-то там? Вы утверждаете о неких рамках ООП и говорите о разболтанности JS, относительно этой сущности. Мне стало интересно, в каких конкретно моментах это коснулось JS?

.ps: кстати сказать, «ООП рамки» понятие размытое (с таким расчетом можно говорить о любом языке, что он не вписался в эти рамки).
О, черт :)
Только не надо еще раз заводить бодягу про прототипно-ориентированный язык и о том, что ооп в изначальном смысле вовсе не ограничивалось тем видом, что представлен в языке SIMULA-67 (и который используют C++ и Java), то есть, не строилось на классах и их наследовании. Все в курсе, книжки и статьи читают, под(скрин)касты слушают/смотрят :)
> что ооп в изначальном смысле вовсе не ограничивалось

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

Наоборот, я с вами согласен :)
сейчас столько вкусных js framework'ов что даже не хочется свой велик изобретать. лучше научиться экстендится от них
Я считаю, что, не понимая хотя бы в общих чертах, как работают фреймворки и что такое правильный и хороший js-код, а также, как работают браузеры, трудно писать хорошие, быстрые, мощные, защищенные от утечек памяти RIA, даже используя великолепные фреймворки вроде перечисленных во вступлении.

Именно этому — показать, хотя бы в общих чертах, как пишется правильный js-код, и как это делают фреймворки, и посвящена эта статья.
> показать, хотя бы в общих чертах, как пишется правильный js-код

Да дофига недочетов у Вас, на самом деле. Вы говорите о правильном JS-коде, однако не используете при этом JS-специфичное делегирование к прототипам (а наследование на них; к примеру, может быть Panel -> Windwo -> Dialog -> и т.д. — виджеты могут наследоваться и эффективно расшаривать родительские методы, а не плодить каждый раз одинаковые методы в своем инстансе).
> а наследование на них;

опечатка — и наследование на них;
Этот скрипт может использоваться и один на странице. Этот пост не про написание собственного фреймворка. Тому, кто созрел для написания собственного фреймворка, этот пост ничего не даст.
> Этот скрипт может использоваться и один на странице.

Code reuse методом copy-paste — сами понимаете, что за «метод». Я имею в виду, если у Вас будет WidgetPanel с набором методов, а дальше появится WidgetWindow, который будет иметь лишь небольшие отличия, Вы будете все методы повторять вручную в WidgetWindow, чтобы WidgetWindow мог один использоваться на странице.

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

Спасибо, «оценил» :)
начинающим разработчикам просто необходимо попрактиковаться на таких великах прежде, чем начинать от чего-то экстендиться.
Может, я чего-то не понимаю?=)
То, что в примере — реализуется простейшей отрисовкой дива и назначением хендлеров

Что тут особенного?
Откройте любой учебник/книгу по любому языку программирования, прочитайте любую главу и скажите то же самое.

Я тут уже примерно на ваш вопрос отвечал.
> addListener
> removeListener

Данные методы описаны не оптимально. На кой черт каждый раз внутри проверять addEventListener / attachEvent, если можно сделать эту проверку единожды при инициализации библиотеки и вернуть соответствующие функции (таким образом, при навешивании событий, никаких проверок уже не будет).

> show:
> hide:

Вы там что-то о «мудаках» в статье говорили? Так вот скажите, почему у меня каждый новый dialog-объект будет иметь эти одинаковые по семантике методы? Не лучше ли их вынести в прототип и делегировать к ним? А если (в теории) будет миллион dialog-объектов? То будет миллион одинаковых функций (в то время, как могла бы быть одна).
Спасибо за интересный комментарий.

По поводу listener'ов:

Да, я тоже об этом думал. А еще я думал о том, что, к примеру, это окно может вызываться как оповещение «сейчас будет тяжелый запрос», и потом начнутся тяжелые вычисления, так не лучше ли мне вызывать еще все методы через setTimeout, а еще лучше, сделать объект очередь и в него добавлять все вызовы функций? И еще много в таком же духе думал, пока не понял, что такого рода размышления меня привели бы не к написанию поста, а написанию фреймворка.

Это простой учебный объект, который очень мало весит и очень мало умеет, но делает свое дело правильно.

По поводу show/hide: А зачем это городить, если будет один такой объект на странице? А если не один, и не будет, то что мешает вам взять его за основу, и переработать?

Видимо, корень нашего с нами непонимания состоит в том, что вы ожидаете полноценный виджет, равный по функциональности лучшим представителям библиотек YUI, Ext JS. Но написание такого виджета — вовсе не цель этой статьи.
> Видимо, корень нашего с нами непонимания состоит в том

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

> не лучше ли мне вызывать еще все методы через setTimeout

там, где надо будет делать псевдо-мультипоточность и делиться ресурсами, давая возможность выполняться другому js-коду, — лучше.

> По поводу show/hide: А зачем это городить, если будет один такой объект на странице?

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

Насчет конкретики/общего случая — в принципе, вы правы. То есть я согласен. Но при написании этого скрипта я планировал использовать его еще для одного поста. Этот пост будет в ближайшее время (сегодня/завтра) и будет строиться на том, что разработчику достаточно включить этот (имеется ввиду сегодняшний) скрипт однократо, и вызовется это окно также один раз. Это соображение, вероятно, и на подсознательном уровне создало у меня такое «ТЗ». То есть скрипт, который вызывается один раз на странице и «все свое» носит с собой :)

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

Относительно все это. Те, кто идут в Гугл по преведенному Вами запросу, — может, и не программисты вовсе (может, у них и не стоит задача знать JS, но скрипт готовый нужен (да и еще и устанавливается в три строчки :)); поэтому — какие они Вам «мудаки»?). Если говорить о программистах — также, может человек только серверной частью занимается, и глубоко JS знать ему и не хочется (а готовый скрипт установить вполне может) — тоже, какой он Вам «мудак»? Относительно всего этого, мнить себя гуру (на фоне вот этих персонажей) — тоже сомнительно (поскольку есть люди, действительно, очень хорошо знающие JS — на глубоком теоретическом уровне).

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

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

Ладно, тоже с этим закончим, а то оффтопа много уже )
С одной стороны, я не могу не признать, что определенная прелесть в ваших рассуждениях есть — что-то гуманистическое и светлое.

С другой стороны, я не склонен оправдывать всех и каждого — на мой взгляд, смысла в этом нет никакого. Да, никто ни в чем не виноват, и у всех есть свои резоны поступить именно так, а не иначе. Но мне-то тоже мало до этого дела. Я вижу то, что вижу, и оцениваю со своей позиции, не претендуя на объективность. «Имхо» я не пишу в каждом предложении и в каждом посте/комментарии лишь по той причине, что считаю это бессмысленным — если я это написал, то уж наверное, это и есть мое мнение.

Отдельно насчет вашего совета насчет «помогайте желающему знать» — надо будет запомнить, мне очень нравится.
>… ваше кофе сбежало!
кофе — он
Спасибо, поправлю.
кстати, говорят, после реформы русского языка, можно стало говорить кофе — «оно»; хотя, я (вроде как по старинке уже, получается) говорю «он» =))
кофе было «он» тогда, когда оно было не «кофе», а «кофий»
я в курсе (так же, по аналогии, с метро — метро был «он», поскольку — метрополитен), но, тем не менее, «он» и был «он»; а вот, говорят, что после реформы, кофе «оно» может быть (но, вероятно, не принудительно — можно и «он», и «оно»)

более того, я слышал, что после этой реформы ВУЗ можно писать теперь маленькими буквами — «вуз».

Информация мной лично не проверена, но получена от человека, который преподает в одном из универов; по его словам, там даже принялись, как оголтелые, исправлять документы с «ВУЗ» на «вуз»
вообще, это все такие условности… но да — привычка =)
Спасибо за подробный разбор полётов, надо будет попрактиковаться.

А что имелось ввиду под
можно сделать гораздо лучше

не использовать innerhtml?

PS много опечаток по тексту и в комментариях к листингу, попробуйте вычитать свой текст.
Спасибо.

>А что имелось ввиду под
Ну, путей улучшения масса — почитайте, к примеру, комментарии от Zelenka или dsCode.

А еще лучше — возьмите исходный код сходного виджета от какого-нибудь фреймворка и посмотрите, как он сделан.

Что касается самого innerHTML — в данном случае он, по большому счету лишний. Аналогичной скорости можно было бы добиться и по стандартам: createElement, appendChild и так далее. Но листинг бы чрезмерно разросся — нужно парсить строку, разбивать на элементы, и все в таком духе.
а почему «typeof foo === 'undefined'», а не «foo === undefined »?

undefined не является зарезервированным словом в JS. Поэтому, если кто-то напишет, скажем

var undefined = 2;

или того хуже

undefined = 2;

то все станет плохо
тогда можно уже рекомендовать выносить конструктор виджета отдельно от описания компонента
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории