diff --git a/index.html b/index.html index f986717..70a42ee 100644 --- a/index.html +++ b/index.html @@ -108,7 +108,7 @@
diff --git a/index_ru.html b/index_ru.html new file mode 100644 index 0000000..ed64d49 --- /dev/null +++ b/index_ru.html @@ -0,0 +1,1265 @@ + + +
++ В наши дни большинство людей, начинающих использовать JavaScript, сталкиваются с непростой задачей выбора библиотеки + для дальнейшего использования, или, по крайней мере, какую из них изучать в первую очередь. + Если вы работаете в какой-либо компании, то выбор, вероятно, уже сделан за вас, и тогда этот вопрос отпадает. Тем не менее, если + вы привыкли к jQuery, а компания заставляет использовать MooTools, + эта статья все-таки может оказаться вам полезной. +
++ Каждый день + в твиттере + я вижу множество постов, которые сводятся к "MooTools или jQuery?". Эта статья поможет вам определиться с выбором. +
++ Я — разработчик MooTools. Я работаю над этим фреймворком. Я веду блог про MooTools. Я написал + основное онлайн руководство и + книгу о MooTools. + Очевидно, моя точка зрения несколько предвзята. Подчеркну также, что я не особо часто использую jQuery. + Если вы разработчик jQuery и увидели, что я исказил что-нибудь, пожалуйста, свяжитесь со + мной, чтобы помочь исправить это недоразумение. Моя задача здесь — помочь людям сделать выбор, + а не выставлять один фреймворк перед другим в более выгодном свете. +
+ ++ Желание помочь вам выбрать между jQuery и MooTools заставляет меня рассказать вам, насколько + они отличаются друг от друга. Начну с того, что они оба являются прекрасными фреймворками. Сделать неправильный выбор здесь невозможно. + Разумеется, у каждого из них есть свои достоинства и недостатки, но, в целом, они оба — отличный выбор. + Есть также и другие фреймворки, которые стоят того, чтобы взглянуть на них более подробно. Dojo, + Prototype, YUI, + Ext и прочие — тоже прекрасный выбор. Какой именно из них подойдет, + больше зависит от вашего стиля и от того, что именно вы хотите сделать. Цель данной статьи — сфокусироваться + на MooTools и jQuery, так как именно из них двоих все больше и больше людей пытаются выбирать. В конце концов, + я не пытаюсь никого убедить переключиться с одного фреймворка на другой. В них обоих есть что почерпнуть + и чему научиться. Более подробно о том, что побудило меня написать эту статью, вы можете прочитать + в моем посте на Clientcide. +
+ ++ | Ядро jQuery | +Ядро MooTools | +
---|---|---|
Размер библиотеки | +55.9K | +64.3K | +
Особенности | +||
Лицензия | +MIT & GPL | +MIT | +
Функции для работы с DOM | +есть | +есть | +
Анимация | +есть | +есть | +
Обработка событие | +есть | +есть | +
CSS3 селекторы | +есть (подмножество) | +есть (подмножество) | +
Ajax | +есть | +есть | +
Нативные расширения (кроме Element) | +около 12 для Array, Object, и String | +70+ для Array, Object, String, Function, и Number | +
Наследование | +Напрямую не поддерживается jQuery | +Предоставляется конструктором Class | +
Прочие соображения | +||
Плагины | +Сотни неофициальных плагинов — plugins.jquery.com | +Около 50 официальных плагинов тут — mootools.net/more. Неофициальные плагины тут — mootools.net/plugins. | +
Официальная библиотека UI | +есть | +нет | +
+ Информация основана на данных jquery.com, mootools.net, и wikipedia.com. +
+ + ++ Если вы зайдете на сайт jQuery, вот что вы увидите вверху страницы: +
++ jQuery — быстрая и компактная JavaScript библиотека, которая упрощает работу с HTML документами, + обработкой событий, анимацией и Ajax для быстрой веб-разработки. jQuery cоздан, чтобы изменить + то, как вы обычно пишете JavaScript. ++
+ ...а вот что написано на официальном сайте MooTools: +
+MooTools — это компактный, модульный, объектно-ориентированный JavaScript фреймворк, созданный для + JavaScript разработчиков среднего и продвинутого уровня. Он позволяет писать мощный, гибкий и кроссбраузерный + код с элегантным, понятным, логичным и хорошо документированным API. ++
+ Я думаю, это действительно все неплохо суммирует. Если вы спросите меня (а поскольку вы это читаете, + я полагаю, что вы уже спросили), вопрос не в том, какой фреймворк лучше или хуже. А в том, что из вышеперечисленных вещей + вы хотели бы делать? Эти два фреймворка просто разработаны с разной целью. Разумеется, есть + некоторая функциональность, которая присутствует в них обоих, но, тем не менее, они не пытаются делать одно и то же. +
++ Описание jQuery говорит о HTML, событиях, анимациях, Ajax и веб-разработке. MooTools говорит об + объектно-ориентированности и написании мощного и гибкого кода. jQuery стремится "изменить то, как вы обычно пишете JavaScript", + в то время как MooTools разработан для разработчиков среднего и продвинутого уровня. +
++ Важно различать концепции фреймворка и набора инструментов (toolkit). MooTools — это фреймворк, который + пытается сделать JavaScript таким, каким он должен быть (согласно авторам MooTools). + Его цель — реализовать API, который выглядел бы как JavaScript, но расширял бы все, не только DOM. + jQuery — это toolkit, который дает вам удобный набор методов, которые делают работу с DOM более приятной. + Просто так получилось, что DOM — это то, на чем концентрируется большинство людей, которые пишут JavaScript, + так что, в большинстве случаев jQuery — все, что вам нужно. +
++ Большая часть кода, которую вы пишете, используя MooTools, все еще выглядит как JavaScript. + Если вам не интересен JavaScript как язык, то изучение MooTools, скорей всего, станет для вас неприятной рутиной. + А если вам интересен JavaScript сам по себе, и то, что делает его таким мощным и выразительным, то + лично я думаю, что MooTools подойдет вам больше. +
+ + ++ Во-первых, jQuery, по большому счету, легче в освоении. Стиль его кода близок к разговорному и даже почти не + ощущается как программирование. Если вам нужно склепать что-нибудь по-быстрому, не изучая JavaScript, то + jQuery, вероятно, лучший выбор для вас. Это не значит, что MooTools не сможет вам помочь в таких вещах, но + я признаю, что MooTools может оказаться слегка сложнее в изучении, если вы новичок в JavaScript, а также + что ресурсов, готовых помочь в изучении jQuery, ощутимо больше, чем аналогичных для MooTools. +
++ Если вы сравните сообщество jQuery (смотрите страницу "Обсуждение" на сайте jQuery) + и сообщество MooTools (irc, + mailing list, и + unofficial forum), + вы быстро обнаружите две вещи: + 1) сообщество jQuery гораздо больше (я приписываю это большей частью тому, насколько легче его изучать, однако есть еще одна причина...), + 2) оно более активно продвигает свою библиотеку. + Если вы измерите jQuery и MooTools с той точки зрения, сколько + человек их использует, сколько запросов о них делается в Гугле, сколько было продано книг и так далее, + вы увидите, что jQuery находится впереди с большим отрывом. +
++ Чтобы рассказать о том, почему вам, возможно, стоит поглядеть в сторону MooTools, я сперва должен поговорить о том, + что вообще оба эти фреймворка делают. В конечном счете, какой фреймворк вы выберете, зависит от того, что вы хотели бы + получить, и как вам нравится программировать (а может быть, и нравится ли вам программировать вообще, + по крайней мере на JavaScript). +
+ + ++ Важно понять, что именно вы хотите делать с помощью JavaScript. Давайте рассмотрим "чистый" JavaScript. Без фреймворков, просто старый добрый JS. + JavaScript предоставляет изначально нативные объекты вроде + Strings, + Numbers, + Functions, + Arrays, + Dates, + Regular Expressions + и так далее. + JavaScript также предоставляет вам способ наследования — довольно эзотерический способ, + называемый прототипным наследованием + (о котором мы поговорим позже). Вот эти строительные блоки и концепция наследования — хлеб с маслом + любого языка программирования, и они не имеют совершенно никакого отношения к браузерам, вебу или CSS с HTML. + Вы можете написать на JavaScript все, что хотите. Крестики-нолики, шахматы, обработчик фотографий, + веб-сервер, что угодно. Просто так получилось, что 99% всего JavaScript запускается в браузерах, и поэтому + мы так о нем думаем, как о языке программирования для браузеров. +
++ Понимание того, что браузеры и DOM — всего лишь то, для чего мы исторически больше всего используем + JavaScript, а на самом деле это очень надежный и выразительный язык программирования, поможет вам + понять различия между MooTools и jQuery. +
+ + ++ Если все ваши задачи, которые вы хотите решить с помощью JavaScript — это "взять эту штуку + со страницы и сделать с ней вот эти штуки", то jQuery, вероятно, для вас лучший выбор. + Ему прекрасно удается предоставлять очень выразительный способ описания поведения объектов на странице, + который иногда даже не похож на программирование. Вы по-прежнему можете использовать остальную часть + JavaScript для других целей, но если вы в основном сконцентрированы на DOM — изменении CSS свойств, + анимации объектов, получении данных через AJAX и тому подобном — большая часть того, что вы пишете, + будет покрыта jQuery, и эта часть не будет выглядеть как старый добрый JavaScript. + jQuery предоставляет несколько методов, не относящихся к DOM. Например, механизм для итерации + по массивам — $.each(array, fn) — + или, например, функцию для обрезания строк — $.trim(str). + Но этих методов там совсем немного, что и хорошо, поскольку в большей части кода вы просто + получаете всякие штуки из DOM, итерируете по ним и меняете каким-либо образом (добавляете html, + изменяете стили, добавляете обработчики события для click и mouseover и т.п.), и вам особо + ничего больше не нужно. +
++ Но если вы подумаете о JavaScript в более широком смысле, вы увидете, что jQuery не фокусируется на + вещах помимо DOM. Это, кстати, одна из причин, почему его так легко изучать, но это также ограничивает + вас в предоставляемых библиотекой возможностях. Он даже просто не пытается быть чем-то большим, + чем отличной системой программирования для DOM. Он не обращает внимания ни на наследование, + ни на все нативные типы в языке JavaScript, но ему этого и не нужно. Если вам нужно возиться со + строками, датами, регулярными выражениями, массивами и функциями, без проблем. Просто это уже + не работа jQuery. К вашим услугам обычный JavaScript. jQuery делает вам конфетку из DOM, но все остальное + уже выходит за его рамки. +
++ Вот в чем отличие MooTools. Вместо того чтобы фокусироваться только на DOM (хотя, как вам дальше будет + видно, он предлагает всю ту же функциональность, что и jQuery, просто в совершенно другой манере), + MooTools включает в свои рамки весь язык. Если jQuery делает вам конфетку из DOM, MooTools пытается + сделать конфетку из самого JavaScript, и это одна из причин, по которой его сложнее изучать. +
+ + ++ Язык программирования JavaScript имеет несколько замечательных особенностей. Во-первых, это + функциональный язык, что означает, + что функции в нем являются объектами высшего порядка, которые могут передаваться повсюду в качестве + переменных, как и любые другие объекты, например, строки и числа. Его создавали, держа в уме эту + концепцию, и большинство его методов и подходов работают лучше всего, если вы пишете код в этом стиле. + Есть некоторые различия между: +
+for (var i = 0; i < myArray.length; i++) { /* делать всякие штуки */ }+
+ и +
+myArray.forEach(function(item, index) { /* делать всякие штуки */ });+
+ В JavaScript особенная модель наследования, + которая не то что бы уникальна, но, по крайней мере, довольно редко встречается в языках программирования. + Вместо классов, которые нужно объявлять отдельно, чтобы из них создавать подклассы, здесь используется + прототипное наследование. + Это означает, что объекты наследуются напрямую от других объектов. Если вы обращаетесь к свойству + какого-нибудь объекта, который наследуется от другого объекта, язык проверяет наличие данного свойства + у наследника, и если не находит, ищет такое свойство у родителя. Вот как этот метод работает, скажем, + на массивах. Когда вы печатаете: +
+[1,2,3].forEach(function(item) { alert(item) }); // выводит сначала 1, потом 2, потом 3+
+ метод "forEach" + не является свойством массива, который вы объявили ([1,2,3]), это общее свойство прототипа + для всех массивов. Когда вы обращаетесь к этому методу, JavaScript ищет метод forEach в вашем массиве + и, не найдя, ищет его в прототипе всех массивов. Это означает, что метод forEach не хранится в памяти + для каждого отдельно взятого массива, а хранится в одном месте только для прототипа массивов. Это невероятно + эффективно и довольно мощно. (Замечание: в MooTools метод forEach доступен как each). +
+ + ++ В JavaScript есть ключевое слово "this". Сложно кратко сказать, что это вообще такое, но, по умолчанию, + "this" — это тот объект, которому принадлежит текущий метод. Это позволяет объектам ссылаться + на самих себя, а иначе они бы не имели такой возможности. Это становится важным, когда вы создаете + много дочерних объектов. Как иначе эти объекты могли бы сослаться на самих себя в своих же методах? + Когда настоящий метод расположен не в дочернем объекте, а в родителе, "this" позволяет + дочернему объекту обращаться к своему состоянию, а не к состоянию родителя. + (Здесь гораздо более подробно рассказано про "this", + и вот еще от Мозиллы.) +
++ Ключевое слово "this" позволяет объектам, наследующимся от других объектов, обращаться к самим себе, + но бывают случаи, когда нужно обращаться через "this" к чему-нибудь другому. Это называется + binding (привязывание), + когда вы определяете другой "this" для метода. Метод "each" для массивов позволяет вам + передать вторым параметром связанный объект. Вот пример того, где вам может понадобиться передавать другой + "this": +
+var ninja = { + weapons: ['катана', 'метательные звездочки', 'супер техника ударов ладонями, взрывающая сердца'], + log: function(message) { + console.log(message); + }, + logInventory: function() { + this.weapons.each(function(weapon) { + // мы хотим, чтобы "this" ссылался на ниндзю + this.log('У этого ниндзи есть ' + weapon); + }, this); // так что мы передаем "this" (который ниндзя) в Array.each + } +}; +ninja.logInventory(); +// У этого ниндзи есть катана +// У этого ниндзи есть метательные звездочки +// У этого ниндзи есть супер техника ударов ладонями, взрывающая сердца+ +
+ В примере выше мы привязываем ниндзю (который "this" внутри метода logInventory) к методу, + который мы передаем массиву, так что мы можем обращаться к свойству log у ниндзи. Если бы мы этого + не сделали, "this" был бы объектом window. +
++ Это только пара примеров силы и выразительности языка JavaScript — наследования, ссылок на самих себя + и связывания, а также эффективного использования свойств в прототипах. Плохие новости в том, что + чистый JavaScript не предоставляет удобных возможностей работать со всеми этими вещами, и тогда на + сцену выходит MooTools. Он превращает эти подходы в простые и приятные в использовании. В итоге + вы пишете более абстрактный код, и, по большому счету, это хорошо. Научиться использовать эти подходы + правильно требует усилий, но, в конечном счете, ваш код с большей вероятностью можно будет повторно + использовать и гораздо легче поддерживать. Поговорим об этих двух вещах более подробно. +
+ + ++ Поскольку MooTools стремится превратить API JavaScript в более стабильный и логичный, + он меньше фокусируется на том, чтобы предоставить вам интерфейс, который "изменит то, как вы обычно пишете + JavaScript", а больше на том, чтобы сделать JavaScript в целом менее мучительным в использовании. + MooTools — это расширение языка JavaScript. Он пытается сделать из JavaScript то, чем он должен + быть. Значительная часть ядра библиотеки посвящена расширению Function, String, Array, Number, + Element и других прототипов. Также, очень важная часть — функция Class. +
++ Class для многих людей выглядит как попытка воссоздать более классическое + наследование, как в Java или C++, но + это не так. + Основная задача Class — сделать модель прототипного наследования более простой + в использовании. Замечу, что этот подход есть не только в MooTools, другие фреймворки предлагают + похожую функциональность, но в jQuery этого нет. jQuery не предлагает ни системы наследования, + ни расширений для обычных объектов (Function, String и т.п.). Это не недостаток jQuery, так как его + авторы легко могли бы добавить такую функциональность, но они разрабатывали библиотеку совершенно + с другой целью. В то время как MooTools стремится сделать JavaScript более крутым, jQuery делает + DOM более крутым, и его разработчики решили ограничить масштаб проекта только этой задачей. +
+ + ++ И поэтому jQuery более доступен. Он не заставляет вас учить JavaScript с головы до пят. + Он не кидает вас в дебри прототипного наследования, связываний, "this" и тому подобного. + Когда вы начинаете изучать jQuery с его официального руководства, + вот первый пример кода, который вы увидите: +
+ +window.onload = function() { + alert("welcome"); +}+ +
а вот третий:
+ +$(document).ready(function() { + $("a").click(function(event) { + alert("Thanks for visiting!"); + }); +});+ +
+ Если вы читали + the MooTools book + или MooTools tutorial (и то, и другое написал я), + они начинаются совсем с других вещей. + Вы могли бы пропустить основы и начать читать об эффектах на странице и о DOM, но если вы хотите + изучить MooTools, придется начать с вещей типа Class, и я признаю: + если вы новичок в программировании, или просто хотите, чтобы на вашем сайте что-то быстро + заработало, а вам бы не пришлось изучать JavaScript, скорей всего, jQuery вам понравится гораздо больше. +
++ С другой стороны, если вы хотите изучить сам JavaScript, MooTools — отличный способ это сделать. + Если вы привыкли программировать, особенно в функциональном и объектно-ориентированном стилях, + у MooTools есть много чего вам предложить. +
+ + ++ Если вы взглянете на вещи, которые может делать jQuery, вы увидите, что + часто у них есть аналог в MooTools. Если вы взглянете на вещи, которые может делать MooTools, + часто не найдется способа повторить их с помощью jQuery, поскольку jQuery сфокусирован только на DOM. + MooTools обладает более широкой функциональностью нежели jQuery, но в этом нет ничего плохого. + Например, jQuery не предлагает никакой системы наследования, ну и хорошо. Вы можете использовать Class + из MooTools вместе с jQuery, если хотите (или написать свою). Есть даже + плагин для наследования в jQuery + (Я его не использовал, но предполагаю, что он предоставляет весьма схожую функциональность). +
++ Если мы посмотрим на пример из jQuery выше: +
+ +$(document).ready(function() { + $("a").click(function(event) { + alert("Thanks for visiting!"); + }); +});+ +
+ и захотим перевести это на MooTools, то получится: +
+window.addEvent('domready', function() { + $$('a').addEvent('click', function(event) { + alert('Thanks for visiting!'); + }); +});+
+ Довольно похоже, нет? +
++ Вот более сложный пример из jQuery: +
+ +$(document).ready(function() { + $("#orderedlist li:last").hover(function() { + $(this).addClass("green"); + }, + function() { + $(this).removeClass("green"); + }); +});+ +
+ и из MooTools: +
+ +window.addEvent('domready',function() { + $$('#orderedlist li:last-child').addEvents({ + mouseenter: function() { + this.addClass('green'); + }, + mouseleave: function() { + this.removeClass('green'); + } + }); +});+ +
+ И снова очень похоже. Я бы сказал, что версия MooTools более явная, но поэтому и писать приходится чуть больше. + Глядя на код для MooTools, понятно что мы добавляем два события — одно для mouseenter и одно для mouseleave, + в то время как версия для jQuery более краткая. Его метод hover + принимает две функции — первую для mouseenter и вторую для mouseleave. + Лично мне нравится, что код для MooTools более разборчивый, но это мое субъективное наблюдение. +
+ ++ Я бы сказал, иногда jQuery может быть слишком эзотерическим, на мой вкус. Например, мне не очевидно, + что делают методы из примера выше, если просто на них посмотреть, и поэтому этот код сложнее прочитать. + Хотя, это может быть несправедливо, так как я глубоко знаю MooTools, поэтому читать код MooTools для меня + легче. Но есть одна вещь, которую я очень ценю в MooTools — это то, что почти все методы и + названия классов обозначают именно то, как и называются. Методы почти всегда — глаголы, и практически + всегда по названию понятно, что они делают. Любой язык программирования требует время от времени пойти + и заглянуть в документацию, чтобы посмотреть синтаксис, и я не говорю, что в MooTools этого делать не надо, + я просто говорю, что нахожу API MooTools более понятным и последовательным. +
+ + ++ Но что если вам нравится синтаксис jQuery? Не проблема, я покажу, как просто можно изменить синтаксис + MooTools на любой вкус. Если бы, например, мы хотели создать метод hover, как в jQuery, мы могли бы + просто сделать так: +
+ +Element.implement({ + hover : function(enter,leave){ + return this.addEvents({ mouseenter : enter, mouseleave : leave }); + } +}); + +// и теперь используем его точно так же, как в jQuery +$$('#orderlist li:last').hover(function(){ + this.addClass('green'); +}, +function(){ + this.removeClass('green'); +}); ++ +
+ В самом деле, для MooTools есть плагины, которые делают именно это. + То, что MooTools фокусируется на расширяемости, означает, что вы можете реализовать все, что захотите. + Это то, что jQuery не умеет. MooTools может маскироваться под jQuery, а jQuery под MooTools — нет. + Если вы захотите писать классы, или расширять существующие прототипы, или делать другие вещи, которые + умеет MooTools, вам придется писать это самим. +
+ + ++ Давайте взглянем на кое-что еще. Вот немного jQuery (из официального руководства): +
+ +$(document).ready(function() { + $('#faq').find('dd').hide().end().find('dt').click(function() { + $(this).next().slideToggle(); + }); +});+ +
+ Это пример синтаксиса, который лично я не очень люблю. Глядя на кусок кода вверху, я с трудом смогу + сказать, что он делает. Особенно интересно, что делает .end и как .find, который идет + за ним, относится к тому, что делает .end? Поглядев в документацию jQuery, становится понятно, + что делает .end (он сбрасывает до значения самого первого селектора, в данном случае #faq). + Но для меня это выглядит очень странно. Когда я работаю с jQuery, я часто обнаруживаю, что не уверен, + что какой-либо метод собирается мне вернуть. Очевидно, это не беспокоит больше никого, так как + многие люди используют jQuery и вполне счастливы, так что припишу это опять своим личным предпочтениям. +
++ Давайте посмотрим, как это выглядело бы в MooTools: +
+ +window.addEvent('domready', function() { + var faq = $('faq'); + faq.getElements('dd').hide(); + faq.getElements('dt').addEvent('click', function() { + this.getNext().slide('toggle'); + }); +}); ++ +
+ И снова, кода для MooTools слегка побольше, но он зато и более явный. Также заметьте, что + подход здесь заключается в хранении ссылки на #faq в переменной, тогда как jQuery + использует специальный метод .end, чтобы вернуться к нему. В MooTools тоже возможно + написать код в одну цепочку, например: +
+item.getElements('input[type=checkbox]') + .filter(function(box) { + return box.checked != checked; + }) + .set('checked', checked) + .getParent()[(checked) ? 'addClass' : 'removeClass']('checked') + .fireEvent((checked) ? 'check' : 'uncheck');+ +
+ Но, в самом деле, писать код вроде этого — куча логики в выражении domready — в любом + фреймворке, само по себе не очень хорошо. Гораздо лучше разбить вашу логику на куски, пригодные для + повторного использования. +
+ + ++ Когда вы работаете над веб-проектом, писать код таким образом очень заманчиво. Просто добавить на страницу + немного кода, который выбирает элементы из DOM, и "обрабатывает их", скрывая одни, изменяя другие и + добавляя обработчики событий click и mouseover. Писать код таким образом очень эффективно и очень быстро. + Однако, проблема в написании всей логики в выражении domready в том, что у вас в итоге окажется + множество кода в разных местах, делающее одно и то же. Если взять код про FAQ из примера выше, + мы можем легко поместить такую же логику в другое место, на другую страницу, с любым списком + заголовков и определений. Надо ли нам повторять ту же самую логику каждый раз, когда мы сталкиваемся с + подобной задачей? +
++ Простой способ написать реюзабельный код — это обернуть его в функцию и передать ей аргументы. + Вот как это может выглядеть на jQuery: +
+ +function faq(container, terms, definitions) { + $(container).find(terms).hide().end().find(definitions).click(function() { + $(this).next().slideToggle(); + }); +}; +$(document).ready(function() { + faq('#faq', 'dd', 'dt'); +});+ +
+ Это гораздо лучше по двум большим и важным причинам: +
++ На самом деле, у jQuery есть немного более проработанная система для написания "виджетов" вроде этих, + пригодных для повторного использования. Вместо того, чтобы поощрять вас разбивать код на функции, + как в предыдущем примере (что и правда довольно грубо), он побуждает вас писать + jQuery плагины. + Вот как это примерно может выглядеть: + +
jQuery.fn.faq = function(options) { + var settings = jQuery.extend({ + terms: 'dt', + definitions: 'dd' + }, options); + // "this" - это текущий контекст, + // в данном случае - элементы, которые мы хотим превратить в разделы FAQ + $(this).find(settings.terms).hide().end().find(settings.definitions).click(function() { + $(this).next().slideToggle(); + }); + return this; +};+ + + а использовать это вы будете таким образом: + +
$('#faq').faq();+ +
+ Но, глядя на пример выше, видно, что нет большой разницы между объявлением нашей функции faq + таким образом и объявлением ее как обычной функции. Конечно, тогда она не мусорит в глобальном неймспейсе, + но мы могли бы и руками добавить ее в свой неймспейс, что ничуть не сложнее. Присоединив + ее к jQuery, мы получаем возможность добавлять ее в цепочки с другими методами. Другое преимущество + в том, что "this" внутри нашей функции тогда будет являться текущим контекстом всего, что будет + в цепочке к тому моменту. Поэтому, если создавать плагины таким образом, они выглядят совсем как часть + jQuery, но, вообще говоря, наш плагин по существу — обычная + функция, которая принимает текущий контекст, делает с ним разные штуки и затем возвращает, чтобы + следующая функция в цепочке могла им воспользоваться. Ничего особенно сложного в этом нет, поэтому + писать плагины для jQuery довольно легко, т.к. они всего лишь обычные функции. +
+ ++ Заметьте, что в jQuery можно писать более сложные плагины, с методами и хранением состояния. + Это позволяет сделать система плагинов jQuery UI, которая не использует тот механизм, который я + описал выше, в примере с faq. Вместо этого, вы привязываете свой объект к объекту jQuery + (например, $.ui.tabs) и можете потом использовать его в коде примерно как $(selector).tabs(), + чтобы можно было продолжать строить цепочку, как в примерах выше. Однако, поскольку это выражение не + возвращает ссылку на объект, который мы создали для наших табов внутри селектора, вам придется + снова выполнять поиск по селектору, чтобы вызывать его методы. И вместо того, чтобы просто вызвать + myTabInstance.add(url, label, index), вам придется вызывать функции, передавая их имена + строками, например $(selector).tabs('add', url, label, index);. Таким образом, вы + выполняете поиск по селектору дважды, если, конечно, не сохранили результат в переменную, и не имеете + под рукой ссылку на функцию add, чтобы можно было использовать штуки вроде bind или delay. Но поскольку этот + пост про ядро jQuery и ядро MooTools, надо сказать, что данная функциональность предоставляется + jQuery UI и в ядро по умолчанию не входит. +
+ + ++ В MooTools, когда вы хотите создать реиспользуемый код, вы скорее будете использовать либо + Class, либо встроите метод + в один из нативных объектов, например, String. +
++ Вместо того чтобы предлагать вам язык, совершенно отличный от JavaScript по стилю, MooTools + пытается балансировать между созданием своего особого синтаксиса и расширением существующих + методов JavaScript. Например, расширяет прототипы нативных объектов в самом языке и в DOM. Это + означает, что если вам, например, надо написать метод trim для обрезания строк, MooTools рекомендует + включить этот метод прямо в объект String (заметьте, что + String.trim в + MooTools уже есть, так что писать его не надо): +
+ +String.implement({ + trim: function() { + return this.replace(/^\s+|\s+$/g, ''); + } +});+ +
+ Это означает, что вы сможете написать просто " no more spaces on the end! ".trim() и + получить "no more spaces on the end!". Некоторые скажут, что внедрение дополнительных + свойств в существующие прототипы неприемлемо. По этой причине, кстати, MooTools не может + нормально работать с Prototype.js, так как оба эти + фреймворка манипулируют прототипами нативных объектов. Если, например, я объявлю + String.prototype.foo(), и другая библиотека на этой странице объявит такую же функцию, то + победит та, которая сделает это позднее. В некотором смысле это похоже на проблему с объявлением + переменных в глобальной области видимости. Но так уж работает JavaScript. Именно так + JavaScript 1.8 добавил + так много фич — просто поместил их в прототипы. +
++ На самом деле, совмещать два фреймворка и заставлять пользователей скачивать их оба довольно + нехорошо. Единственный случай, когда вам может понадобиться два фреймворка одновременно — + когда вы хотите использовать плагины из них обоих. Однако, по мнению авторов MooTools (и меня + в том числе), если вы хотите использовать плагин, которого нет в вашем фреймворке, но есть в + другом, лучше потратить какое-то время на портирование его на ваш фреймворк, нежели помещать + их оба на страницу и заставлять пользователей скачивать лишний код. +
++ Когда вы понимаете, как работает JavaScript и какие возможности дает расширение нативных объектов, + вам открывается совершенно новый уровень в программировании. Вы можете писать плагины, которые + изменяют прототипы Element, Date или Function. Некоторые могут сказать, что это замусоривает + глобальные объекты, но я возражу, что JavaScript и задумывался, чтобы использоваться именно так. + Это, можно сказать, особенность его дизайна. Код получается более кратким и менее связным, + если ее использовать. jQuery делает почти то же самое, но при этом ограничивает все расширения + прототипов объектом jQuery. +
++ Несмотря на то, что вы можете легко объединять вызовы методов в цепочку, если это методы + объекта jQuery, для других объектов вам придется использовать обычные методы. Например, если + вы хотите обрезать кусок текста с помощью функции trim, а затем пробежаться по всем его строкам, + выполняя какой-то код, вам придется написать: +
+ +$.each( $.trim( $('span.something').html() ).split("\n"), function(i, line){alert(line);});+ +
То же самое с помощью MooTools (так как он модифицирует прототипы):
+ +$('span.something').get('html').trim().split("\n").each(function(line){alert(line);});+ +
+ Этот пример позволяет понять, какие возможности дает изменение прототипов. DOM-элементы — не + единственное место, где может пригодиться объединение методов в цепочки. MooTools позволяет + делать это с методами любых объектов, включая вызов методов, воздействующих на несколько + объектов сразу. +
++ В основе фреймворка MooTools лежит идея того, что если функциональности нет в ядре, вы всегда можете + ее расширить, и получить то, что хотели. Задача ядра — не предоставить все возможные фичи, + которые когда-либо могут вам понадобиться, а предоставить инструменты, чтобы вы могли создать эти + фичи сами. А для этого важно, чтобы можно было легко расширять существующие прототипы и использовать + преимущества прототипного наследования. Это все можно делать и на чистом JavaScript, но с помощью + MooTools это проще и приятней. +
+ + + ++ Несмотря на название, функция Class в MooTools не является классом и не создает никаких + классов. По виду и по способу использования она может напомнить обычные классы в более традиционных + языках программирования, но на самом деле Class целиком и полностью относится к объектам + и прототипному наследованию (к сожалению, для описания этих вещей слово "класс" подошло лучше других, + поэтому когда я буду говорить "классы", имейте в виду, что я говорю про функции, которые возвращают + объекты, которые, в свою очередь, я буду называть "экземпляры", и которые наследуются от прототипа). +
++ Чтобы создать класс, надо передать объект в функцию Class, например, так: +
+ +var Human = new Class({ + initialize: function(name, age) { + this.name = name; + this.age = age; + }, + isAlive: true, + energy: 1, + eat: function() { + this.energy = this.energy + 1; + } +});+ +
+ Мы передаем в Class объект (со свойствами вроде "isAlive" и "eat", как у объекта выше), + и этот объект становится прототипомм для каждого экземпляра полученного класса. Чтобы создать + экземпляр, надо вызвать его вот так: +
+var bob = new Human("bob", 20); // Боба зовут Боб и ему 20 лет.+
+ Теперь у нас есть экземпляр класса Human. У bob доступны все свойства объекта, который мы + указали при создании класса Human. Важно, что все эти свойства он получил при помощи + прототипного наследования, то есть, когда мы обращаемся к bob.eat, мы обращаемся на самом деле + к свойству его прототипа, так как сам bob этого свойства не имеет. JavaScript смотрит на объект + bob, не находит в нем свойства eat, поднимается выше по цепочке наследования и находит + его у объекта, который мы передали в функцию Class, когда создавали класс Human. + То же относится и к свойству energy. На первый взгляд выглядит плохо, так как мы не хотим, + чтобы все "человеки" получали энергию, каждый раз когда bob ест. Но важно понимать, что когда + мы первый раз назначаем значение свойству bob.energy, bob получает свое собственное + свойство, и нам больше не нужно будет лезть за ним в прототип. Так что, когда bob первый раз + поест, у него появится собственное свойство (равное 2), а прототип останется нетронутым. +
+bob.eat(); //bob.energy == 2+
+ Также обратите внимание, что name и age уже являются собственными свойствами bob, так как + они назначаются ему при инициализации (см. пример выше). +
++ Этот подход может показаться слегка странным, но он довольно удобен, чтобы создать шаблон один раз, + а затем создавать экземпляры по этому шаблону, когда понадобится. При этом у каждого экземпляра будет + свое собственное состояние: +
+ +var Alice = new Human(); +//alice.energy == 1 +//bob.energy == 2+ +
+ Но все становится еще интереснее, когда мы хотим расширить это поведение. +
+ + ++ Давайте еще раз взглянем на наш плагин faq для jQuery. Что, если нам понадобится сделать + аяксовую версию, которая будет получать ответы на вопросы с сервера? Представим, что этот плагин + был написан кем-нибудь другим, и мы хотим модифицировать плагин, не внося изменений в исходную + версию (а форкать мы не хотим). +
++ Единственные реальные способы это сделать — либо скопировать весь его код, фактически + форкнув его (напомню, это обычная функция), либо вызвать эту функцию и затем добавить + дополнительную логику, которую мы хотели. Если выбирать, то последнее кажется менее проблематичным. + Вот как это может выглядеть: +
+jQuery.fn.ajaxFaq = function(options) { + var settings = jQuery.extend({ + // какие-нибудь опции, специфичные для ajax + url: '/getfaq.php' + definitions: 'dd' + }, options); + // "this" в данном случае - элементы, которые мы хотим превратить в разделы faq + $(this).find(settings.definitions).click(function() { + $(this).load(.....); // логика для загрузки контента с сервера + }); + this.faq(); // вызываем оригинальный плагин +});+
+ У такого подхода есть подводные камни. Во-первых, нам придется снова пробегать весь DOM в поисках + элементов по селектору, что может быть довольно затратно, а способа сохранить выбранные объекты + и использовать их во второй раз нет. Во-вторых, мы не сможем поместить нашу логику в середину + кода плагина. А реального решения, кроме копирования всего кода, нет. +
++ Теперь давайте рассмотрим наш класс Human для MooTools. Что, если нам понадобится + создать новую версию "человеков" с дополнительными свойствами? Просто расширим класс: +
+var Ninja = new Class({ + Extends: Human, + initialize: function(name, age, side) { + this.side = side; + this.parent(name, age); + }, + energy: 100, + attack: function(target) { + this.energy = this.energy - 5; + target.isAlive = false; + } +});+
+ Как вы видите, мы добавили достаточно много функциональности с помощью подкласса. Теперь у этого + подкласса есть как свойства его родителя, так и его собственные. Например, Ninja имеет + начальное значение энергии, равное 100, также у него есть дополнительный параметр, side + и дополнительный метод attack, который позволяет убивать других человеков, но, правда, + стоит ниндзе энергии. +
+ +var bob = new Human('Bob', 25); +var blackNinja = new Ninja('Nin Tendo', 'unknown', 'evil'); +//blackNinja.isAlive = true +//blackNinja.name = 'Nin Tendo' +blackNinja.attack(bob); +// у Боба не было шансов+ +
+ Есть некоторые интересные вещи, которые стоит рассмотреть подробнее. Обратите внимание на метод + initialize в классе Ninja. Этот метод, очевидно, перекрывает старый метод из + класса Human, но мы все равно имеем к нему доступ через вызов функции this.parent, + передавая ей аргументы, которые ожидает метод initialize у родителя. Тем самым мы можем + контролировать, когда выполнять наш дополнительный код — до родительского или после. + Представьте, если бы мы могли сделать подобное в нашем плагине для jQuery. Тогда бы мы смогли + сначала получить данные с сервера через ajax, а затем открыть раздел faq с красивым эффектом. +
++ В MooTools существует также и другой подход, называемый Mixin. В отличие от создания классов + и их наследования, вы можете создавать классы, чтобы потом смешивать их с другими классами, + наделяя их тем самым нужными свойствами. Например: +
+ +var Warrior = new Class({ + energy: 100, + kills: 0, + attack: function(target) { + target.isAlive = false; + this.energy = this.energy - 5; + this.kills++; + } +});+ +
+ То есть, мы выделили свойства, которые отличают ниндзь от обычных человеков, и поместили в отдельный + класс. Это позволит использовать данный код отдельно от класса Ninja. Можно объявить класс + Ninja другим способом, отдельно указав, что он обладает качествами воина: +
+ +var Ninja = new Class({ + Extends: Human, + Implements: Warrior, // можно передать массив, если классов несколько + initialize: function(name, age, side) { + this.side = side; + this.parent(name, age); + } +});+ +
+ Ninja в этом случае будет работать совершенно так же, но теперь у нас есть класс + Warrior, и его можно использовать повторно: +
+ +var Samurai = new Class({ + Extends: Human, + Implements: Warrior, + side: 'good' +});+ +
+ Теперь мы объявили классы Samurai и Ninja. Но посмотрите, как мало кода занимают + объявления этих классов. Оба они похожи в том, что являются человеками и обладают качествами воина, + но отличаются тем, что самураи всегда-всегда хорошие, а ниндзи могут быть и плохими. Потратив время + на создание классов Human и Warrior, мы теперь с легкостью получили три различных + класса без какого-либо дублирования кода между ними. Такой подход дает возможность более тонко + контролировать, когда какие методы будут вызываться и как они друг с другом соотносятся. + Каждый экземпляр созданных таким образом классов имеет свое собственное состояние, и код получился + весьма читаемым. +
++ Сейчас, когда вы получили представление о том, как работают классы в MooTools, давайте посмотрим + на наш плагин faq для jQuery и перепишем его так, как бы мы сделали в MooTools, а потом + добавим Ajax, как мы пытались сделать в jQuery. +
++var FAQ = new Class({ + // Options - это еще один MooTools класс + Implements: Options, + // опции по умолчанию + options: { + terms: 'dt', + definitions: 'dd' + }, + initialize: function(container, options) { + // сохраняем ссылку на наш контейнер + this.container = $(container); + // setOptions - это метод, предоставляемый Options, + // он смешивает переданные в конструктор свойства с дефолтными + this.setOptions(options); + // сохраняем заголовки и тексты + this.terms = this.container.getElements(this.options.terms); + this.definitions = this.container.getElements(this.options.definitions); + // вызываем наш метод attach + // поскольку мы выделили это в отдельный метод, + // класс будет проще расширять + this.attach(); + }, + attach: function(){ + // пробегаем по заголовкам faq + this.terms.each(function(term, index) { + // добавляем каждому обработчик события click + term.addEvent('click', function(){ + // вызываем наш метод toggle + this.toggle(index); + }, this); + }, this); + }, + toggle: function(index){ + // показываем/скрываем текст раздела faq по его номеру + this.definitions[index].slide('toggle'); + } +}); ++ +
+ Ого, это довольно много кода. Если даже удалить все комментарии, все равно получится больше 20 строк. + Я уже показывал выше, что мы можем написать такой плагин, уложившись примерно в такое же количество + строк, как и с jQuery. Так почему этот код такой большой? Потому, что мы писали его с заделом на + расширение. Итак, чтобы создать экземпляр faq, просто вызовем конструктор: +
+ +var myFAQ = new FAQ(myContainer); +// и теперь мы можем вызывать его методы +myFAQ.toggle(2); // показать/скрыть третий раздел ++ +
+ Мы имеем доступ к методам и свойствам экземпляра, теперь, что насчет ajax? В нашем jQuery плагине + была проблема, что мы не могли отложить разворачивание раздела, чтобы подождать, пока он подгрузится. + Здесь же нет такой проблемы: +
+ +FAQ.Ajax = new Class({ + // этот класс наследует свойства класса FAQ + Extends: FAQ, + // и получает дополнительное свойство к уже имеющимся дефолтным, + // оно нужно для хранения url, по которому мы будем запрашивать наши разделы + options: { + url: null; + }, + // мы будем кешировать результаты, чтобы не запрашивать данные на сервере + // каждый раз при открытии раздела + indexesLoaded: [], + toggle: function(index){ + // если мы уже загрузили данные для этого раздела + if (this.indexesLoaded[index]) { + // то просто вызываем родительский метод + this.parent(index); + } else { + // иначе, лезем на сервер за данными + new Request.HTML({ + update: this.definitions[index], + url: this.options.url + index, + // и когда они загружены, открываем раздел + onComplete: function(){ + this.indexesLoaded[index] = true; + this.definitions[index].slide('toggle'); + }.bind(this) + }).send(); + } + } +}); ++ +
+ Таким образом, мы получили версию FAQ, которая умеет забирать данные с сервера. Обратите внимание, + что мы смогли интегрировать новую логику так, чтобы раздел не открывался, прежде чем придут данные + (что мы не могли сделать с jQuery). Также заметьте, что нам пришлось всего лишь описать функциональность + ajax без особых лишних телодвижений. Это позволяет создавать целые семейства плагинов, которые + отличаются друг от друга некоторыми свойствами и функциями. Это также значит, что мы можем взять + чужой плагин и изменить в нем лишь то, что нам нужно, не форкая его. Это, кстати, объясняет то, что + для MooTools существует меньше плагинов для различных распространенных штук вроде удобного выбора даты + или интерфейса со вкладками. Большинство плагинов либо решают вашу проблему сразу, либо требуют + незначительных изменений, чтобы полностью вам подходить. +
++ Как я упоминал ранее, возможно писать сложные виджеты с методами и хранением состояния и на jQuery, + но большая часть кода, которую вам придется написать, будет чистым JavaScript, поскольку не имеет + отношения к DOM. А jQuery не предлагает способа расширять свои объекты с помощью подклассов и + не поможет вам создать классы для смешивания с другими, чтобы их можно было использовать еще. + В конечном счете, все плагины jQuery всегда привязаны к элементам DOM. Если вам захочется написать + класс, который, скажем, будет обрабатывать URL'ы, вам придется писать это самому, так как готовой + системы, позволяющей хранить состояние, нет. +
+ + ++ jQuery сконцентрирован на выразительности, возможности быстро и просто написать код, и на DOM, + а MooTools — на расширяемости, наследовании, читаемости, возможности повторного использования + и поддерживаемости. jQuery — это то, с чего просто начать и быстро получить результаты, но + потом, по моему опыту, это может превратиться в код, который сложно использовать повторно и + поддерживать (но, на самом деле, это уж от вас зависит, и не проблема jQuery). MooTools — + то, что сложнее изучать и требует написания большего количества кода, прежде чем вы увидите + результаты, но в итоге получившийся код, вероятно, будет легче поддерживать и использовать повторно. +
++ Дальше, ядро MooTools не содержит всевозможной кучи фич, равно как и ядро jQuery. Оба фреймворка + стараются держать свои ядра компактными, давая другим возможность написать плагины и расширения. + Их задача не предоставить вам все фичи, которые могут вам пригодиться, а дать инструменты, + чтобы вы могли сами создать что вам угодно. В этом сила JavaScript, а также JavaScript фреймворков, + и оба фреймворка в этом весьма преуспели. MooTools подходит к этому более глобально, позволяя + вам писать что угодно, не ограничиваясь лишь DOM, но платит за это более высокой сложностью изучения. + Возможности MooTools включают в себя все возможности jQuery, но jQuery просто концентрируется на + "гладком" API для работы с DOM, и вовсе не мешает вам использовать стандартные средства языка для + прототипного наследования или какую-либо другую систему вроде той, что в MooTools, если хотите. +
++ Вот почему я говорю, что оба фреймворка — прекрасный выбор. Я попытался показать различия + в их философии, а также их преимущества и недостатки. Вряд ли мне удалось удержать свое явное + предпочтение MooTools под контролем, но надеюсь, что этот текст был вам полезен. + Независимо от того, какой фреймворк вы выберете, теперь вы знаете больше о них обоих. + Если у вас найдется драгоценное время, очень рекомендую сделать по сайту на каждом из них. + Затем напишите свой собственный обзор, который, возможно, осветит те вещи, которые я упустил. +
++ +
++ Обо мне: Я разработчик MooTools и веду блог о JavaScript и + других вещах на моем сайте Clientcide. Также я написал + множество плагинов для MooTools. Я автор + MooTools Essentials + и MooTools online tutorial. + Я работаю в компании Cloudera. + Со мной можно связаться здесь. +
+ + +A note on comments here: These comments are moderated. No comments will show up until they are approved. Comments that are not productive (i.e. inflammatory, rude, etc) will not be approved. Similarly, "fan" comments won't be approved either - i.e. no "FrameworkX Rulez! It's better than FrameworkY for realz!" are not constructive comments. +
+ + + +