Статьи

Начало работы с Underscore.js

Эта статья была рецензирована Агбонгхама Коллинз и Райаном Ченки . Спасибо всем рецензентам SitePoint за то, что сделали контент SitePoint как можно лучше!

Underscore.js — это библиотека JavaScript, написанная Джереми Ашкенасом , которая предоставляет функциональные утилиты для различных случаев использования, с которыми мы, как разработчики, можем столкнуться при работе с веб-проектом.

Это делает для кода, который легче читать:

_.isEmpty({}); // true 

Это делает для кода, который легче написать:

 _.flatten([[0, 1], [2, 3], [4, 5]]); // [0, 1, 2, 3, 4, 5] 

Он предлагает функции, для которых нет собственного метода 1: 1:

 _.range(5); // [0, 1, 2, 3, 4] 

Он даже может использоваться как шаблонный движок сам по себе:

 _.template('<p><%= text %></p>', {text: 'SitePoint Rocks!'}); // <p>SitePoint Rocks!</p> 

Underscore — это легковесная библиотека (всего 5,7 КБ, минимизированная и Gzipped), которая используется в различных известных проектах, таких как:

Теперь давайте уточним и начнем погружаться в его основные возможности.

Хорошие части

В этом уроке я собираюсь выделить три наиболее распространенных метода Underscore:

Я объясню, как они используются по отдельности, а затем свяжу их вместе, чтобы создать демонстрационное приложение, которое вы можете найти в конце урока . Как всегда, код для этой демонстрации доступен на Github .

Если вы хотите следовать примерам, вам нужно взять копию библиотеки, например, из вашего любимого CDN:

 <script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script> 

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

_.each : _.each циклы

Нет ни одного проекта, в котором в какой-то момент кода не было бы ничего похожего на этот фрагмент:

 var artists = ['Pharrel Williams', 'Led Zeppelin', 'Rolling Stones']; for(var i = 0; i < artists.length; i++) { console.log('artist: ' + artists[i]); } 

Подчеркивание позволяет вам писать эквивалентный код, используя синтаксис, который является более читабельным:

 var artists = ['Pharrel Williams', 'Led Zeppelin', 'Rolling Stones']; _.each(artists, function(artist, index, artists) { console.log('artist: ' + artist); }); 

Аккуратно, а? _.each() принимает два параметра:

  • Массив (или объект) для перебора.
  • Функция обратного вызова.

Для каждого элемента в нашем массиве _.each() вызовет функцию обратного вызова (в документации упоминается как iteratee ). Внутри обратного вызова мы получаем доступ к еще трем параметрам:

  • Значение массива для текущего индекса итерации ( artist ). Например, для приведенного выше фрагмента мы получили бы «Pharrel Williams» для первой итерации.
  • Номер текущей итерации ( index ), который в нашем случае будет варьироваться от 0 до 2.
  • Массив, который мы перебираем ( artists ).

Как вы можете видеть, код более читабелен, и мы можем получить доступ к отдельным элементам массива без необходимости в artists[i] , как мы видели в примере, в котором использовался цикл for .

Далее мы посмотрим, как ведет себя шаблонизатор.

_.template() : интуитивно понятный и _.template()

Со времени появления одностраничного приложения наличие надежного шаблонизатора внешнего интерфейса стало фундаментальной потребностью в нашем рабочем стеке.

Underscore предоставляет шаблонизатор, который для тех, кто знаком с такими языками, как PHP или Ruby on Rails, покажется довольно знакомым.

Продолжая наш предыдущий фрагмент, мы продемонстрируем, как работает _.template() . Мы сделаем это, добавив пару строк в наш код, как показано ниже:

 var artists = ['Led Zeppelin', 'ACDC', 'Rolling Stones'], artistTemplate = _.template('<li><%= artist %></li>'), content = ''; _.each(artists, function(artist, index, artists) { content += artistTemplate({ artist: artist }); }); var container = document.createElement('ol'); container.innerHTML = content; document.body.appendChild(container); 

Здесь мы _.template() функцию _.template() со строковым аргументом, который включает некоторые данные внутри разделителей ( <%= artist %> ). При таком _.template() возвращает функцию, которую мы можем использовать снова и снова.

Мы можем вызвать нашу новую функцию, используя artistTemplate() , передав ей литерал объекта в качестве аргумента. Это вернет строку, которую мы первоначально передали в _.template() , заменяя любые свойства объекта, которые соответствуют свободным переменным шаблона. В нашем случае <%= artist %> будет заменено значением в атрибуте artist объекта.

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

 var artists = ['Led Zeppelin', 'ACDC', 'Rolling Stones'], artistTemplate = _.template( '<% _.each(artists, function(artist, index, artists) { %>' + '<li><%= artist %></li>' + '<% }); %>' ), content = artistTemplate({ artists: artists }); var container = document.createElement('ol'); container.innerHTML = content; document.body.appendChild(container); 

Мы включили наш вызов _.each() в строку, которая представляет наш шаблон, что приводит нас к изменению способа вызова шаблона. Поскольку теперь мы выполняем итерации внутри функции _.template() , мы можем передать полный массив artistTemplate() в artistTemplate() (ранее мы передавали отдельных художников). Вывод этого кода будет таким же, как в предыдущем примере.

Когда мы хотим, чтобы _.template() оценивал код JavaScript, нам просто нужно окружить наш код между <% %> _.template() <% %> вместо <%= %> .

Поскольку _.template шаблона, сгенерированного _.template работает так же, как и _.template функции, мы можем продвинуть наш фрагмент на один шаг вперед и вызвать один шаблон из другого, используя теги <% %> . Таким образом, мы можем создавать многократно используемые шаблоны, поскольку у нас может быть другой шаблон-обертка для нашего списка исполнителей и просто вызывать шаблон для каждого из элементов, которые он содержит.

Наконец, давайте посмотрим на _.filter() .

_.filter() : все, что вам нужно, это булева функция

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

Наша функция обратного вызова также получит три аргумента, как в случае _.each() : элемент в массиве, соответствующий текущему индексу итерации, индекс итерации и сам массив.

Чтобы прояснить это, давайте внесем несколько изменений в наш фрагмент.

 var artists = ['Led Zeppelin', 'ACDC', 'Rolling Stones'], artistTemplate = _.template( '<% _.each(artists, function(artist, index, artists) { %>' + '<li><%= artist %></li>' + '<% }); %>' ), content = artistTemplate({ artists: _.filter(artists, function(artist, index, artists) { return artist === 'ACDC'; }) }); var container = document.createElement('ol'); container.innerHTML = content; document.body.appendChild(container); 

Как вы уже догадались, в нашем шаблоне мы получим ['ACDC'] в качестве аргумента массива. Вот демонстрация того, что мы получили до сих пор.

Достаточно сказано. Давайте заставим вещи работать на что-то, что имеет немного больше смысла.

Наше демо-приложение

Не забудьте, код для этой демонстрации доступен на Github .

Мы создадим небольшое приложение, которое использует API, отображает полученную информацию и позволяет пользователю фильтровать то, что отображается. Для этого мы будем использовать:

В частности, приложение будет извлекать некоторую информацию об исполнителе из Spotify, и с помощью Underscore _.template , _.each и _.filter мы будем отображать ее на странице и позволять пользователю сузить результаты по жанрам.

Для этого мы разделим наш код на три разных модуля:

  • _isAwesome.Config : содержит информацию, которую мы будем использовать в приложении.
  • _isAwesome.Template : заботится о компиляции шаблона.
  • _isAwesome : это основной модуль, отвечающий за реагирование на действия пользователя и обновление пользовательского интерфейса.

Все они следуют шаблону модуля .

Модуль конфигурации

Модуль Config содержит идентификаторы используемых шаблонов, а также URL-адрес API, который мы запросим, ​​а также идентификаторы исполнителей, которые мы хотим получить из Spotify. Таким образом, мы можем добавить больше художников, просто добавив дополнительные элементы в массив.

Шаблонный модуль

Этот модуль отвечает за компиляцию шаблонов, вызывая getTemplates() в модуле Config .

Основной модуль

Этот модуль отвечает за отправку Ajax-запроса на URL-адрес, который мы получаем из модуля Config и отрисовку содержимого с использованием шаблонов из модуля Template .

Помимо этого, этот модуль также заботится о фильтрации элементов на основе фильтра, по которому щелкнул пользователь.

Оба фильтра и наши шаблоны включены как часть HTML.

Для реализации фильтрации мы будем полагаться на атрибуты данных HTML 5 и интерфейс данных jQuery . Это скорее вопрос удобства, но если вы хотите сделать это изначально, поддержка браузера очень хорошая .

Это разметка кнопок, которые мы будем использовать для фильтрации:

 <button class="btn btn-default sized" data-filter-field="genres" data-filter-value="album rock" data-action="filter">Album Rock</button> 

Это пример объекта, который мы передадим нашей функции фильтра:

 { action: 'filter', field: 'genres', value: 'rock' } 

Мы будем иметь HTML для наших шаблонов как часть нашего index.html внутри <script> , который мы предотвращаем от выполнения, устанавливая его тип в нечто отличное от обычного text/javascript . Просто для согласованности мы установим это underscore/template .

У нас будет два шаблона. Первый будет содержать список художников, а второй будет содержать отдельных художников для отображения. Как мы видели выше, мы будем использовать то, что мы называем встроенными шаблонами . Мы будем вызывать один шаблон ( 'item-tpl' ) из другого ( 'item-list' ).

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

Вот и все.

Вывод

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

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

Как насчет тебя? Ты работал с Underscore? Хотели бы вы попробовать? Вы пробовали альтернативу (например, lodash ), которая предоставляет аналогичные возможности? Позвольте мне знать в комментариях ниже.