Lodash js что это
Перейти к содержимому

Lodash js что это

  • автор:

Шаблонизатор LoDash

Материал на этой странице устарел, поэтому скрыт из оглавления сайта.

В этой главе мы рассмотрим шаблонизацию – удобный способ генерации HTML по «шаблону» и данным.

Большинство виджетов, которые мы видели ранее, получают готовый HTML/DOM и «оживляют» его. Это типичный случай в сайтах, где JavaScript – на ролях «второго помощника». Разметка, CSS уже есть, от JavaScript, условно говоря, требуются лишь обработчики, чтобы менюшки заработали.

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

Зачем нужны шаблоны?

Ранее мы уже видели код Menu , который сам создаёт свой элемент:

function Menu(options) < // . приведены только методы для генерации DOM . function render() < elem = document.createElement('div'); elem.className = "menu"; var titleElem = document.createElement('span'); elem.appendChild(titleElem); titleElem.className = "title"; titleElem.textContent = options.title; elem.onmousedown = function() < return false; >; elem.onclick = function(event) < if (event.target.closest('.title')) < toggle(); >> > function renderItems() < var items = options.items || []; var list = document.createElement('ul'); items.forEach(function(item) < var li = document.createElement('li'); li.textContent = item; list.appendChild(li); >); elem.appendChild(list); > // . >

Понятен ли этот код? Очевидно ли, какой HTML генерируют методы render , renderItems ?

С первого взгляда – вряд ли. Нужно как минимум внимательно посмотреть и продумать код, чтобы разобраться, какая именно DOM-структура создаётся.

…А что, если нужно изменить создаваемый HTML? …А что, если эта задача досталась не программисту, который написал этот код, а верстальщику, который с HTML/CSS проекта знаком отлично, но этот JS-код видит впервые? Вероятность ошибок при этом зашкаливает за все разумные пределы.

К счастью, генерацию HTML можно упростить. Для этого воспользуемся библиотекой шаблонизации.

Пример шаблона

Шаблон – это строка в специальном формате, которая путём подстановки значений (текст сообщения, цена и т.п.) и выполнения встроенных фрагментов кода превращается в DOM/HTML.

Пример шаблона для меню:

Как видно, это обычный HTML, с вставками вида .

Для работы с таким шаблоном используется специальная функция _.template , которая предоставляется фреймворком Lodash, её синтаксис мы подробно посмотрим далее.

Пример использования _.template для генерации HTML с шаблоном выше:

// сгенерировать HTML, используя шаблон tmpl (см. выше) // с данными title и items var html = _.template(tmpl)(< title: "Сладости", items: [ "Торт", "Печенье", "Пирожное" ] >);

Значение html в результате:

Этот код гораздо проще, чем JS-код, не правда ли? Шаблон очень наглядно показывает, что в итоге должно получиться. В отличие от кода, в шаблоне первичен текст, а вставок кода обычно мало.

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

Holy war detected!

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

Эта глава – совершенно не место для священных войн на эту тему.

Далее будет более полный обзор типов шаблонных систем, применяемых в JavaScript, но начнём мы с _.template , поскольку эта функция проста, быстра и демонстрирует приёмы, используемые в целом классе шаблонных систем, активно используемых в самых разных JS-проектах.

Синтаксис шаблона

Шаблон представляет собой строку со специальными разделителями, которых всего три:

Код между разделителями будет выполнен «как есть»

– для вставки expr как HTML

Переменная или выражение внутри будет вставлено «как есть». Например: вставит значение переменной title , а вставит 4 .

– для вставки expr как текста

Переменная или выражение внутри будет вставлено «как текст», то есть с заменой символов < >& » ‘ на соответствующие HTML-entities.

Например, если expr содержит текст
, то при в результат попадёт, в отличие от , не HTML-тег
, а текст <br> .

Функция _.template

Для работы с шаблоном в библиотеке LoDash есть функция _.template(tmpl, data, options) .

tmpl Шаблон. options Необязательные настройки, например можно поменять разделители.

Эта функция запускает «компиляцию» шаблона tmpl и возвращает результат в виде функции, которую далее можно запустить с данными и получить строку-результат.

// Шаблон var tmpl = _.template('; // Результат подстановки alert( tmpl(data) ); // 

Пример выше похож на операцию «поиск-и-замена»: шаблон просто заменил на значение свойства data.title .

Но возможность вставки JS-кода делает шаблоны сильно мощнее.

Например, вот шаблон для генерации списка от 1 до count :

    \ \
  • \ %>\
  • 1
  • 2.
    , потом выполнился код for , который последовательно сгенерировал элементы списка, и затем список был закрыт

Хранение шаблона в документе

Шаблон – это многострочный HTML-текст. Записывать его прямо в скрипте – неудобно.

Один из альтернативных способов объявления шаблона – записать его в HTML, в тег с нестандартным type , например "text/template" :

Если type не знаком браузеру, то содержимое такого скрипта игнорируется, однако оно доступно при помощи innerHTML :

var template = document.getElementById('menu-template').innerHTML;

В данном случае выбран type="text/template" , однако подошёл бы и любой другой нестандартный, например text/html . Главное, что браузер такой скрипт никак не обработает. То есть, это всего лишь способ передать строку шаблона в HTML.

Полный пример цикла с подключением библиотеки и шаблоном в HTML:

Как работает функция _.template?

Понимание того, как работает _.template , очень важно для отладки ошибок в шаблонах.

Как обработка шаблонов устроена внутри? За счёт чего организована возможность перемежать с текстом произвольный JS-код?

Оказывается, очень просто.

Вызов _.template(str) разбивает строку str по разделителям и, при помощи new Function создаёт на её основе JavaScript-функцию. Тело этой функции создаётся таким образом, что код, который в шаблоне оформлен как – попадает в неё «как есть», а переменные и текст прибавляются к специальному временному «буферу», который в итоге возвращается.

Взглянем на пример:

var compiled = _.template(" "); alert( compiled );

Функция compiled , которую вернул вызов _template из этого примера, выглядит примерно так:

function(obj) < obj || (obj = <>); var __t, __p = '', __e = _.escape; with(obj) < \ __p += '

' + ((__t = (title)) == null ? '' : __t) + '

'; > return __p >

Она является результатом вызова new Function("obj", "код") , где код динамическим образом генерируется на основе шаблона:

  1. Вначале в коде идёт «шапка» – стандартное начало функции, в котором объявляется переменная __p . В неё будет записываться результат.
  2. Затем добавляется блок with(obj) < . >, внутри которого в __p добавляются фрагменты HTML из шаблона, а также переменные из выражений . Код из копируется в функцию «как есть».
  3. Затем функция завершается, и return __p возвращает результат.

При вызове этой функции, например compiled() , она получает объект данных как obj , здесь это , и если внутри with(obj) < .. >обратиться к title , то по правилам конструкции with это свойство будет получено из объекта.

Можно и без with

Конструкция with является устаревшей, но в данном случае она полезна.

Так как функция создаётся через new Function("obj", "код") то:

  • Она работает в глобальной области видимости, не имеет доступа к внешним локальным переменным.
  • Внешний use strict на такую функцию не влияет, то есть даже в строгом режиме шаблон продолжит работать.

Если мы всё же не хотим использовать with – нужно поставить второй параметр – options , указав параметр variable (название переменной с данными).

alert( _.template(" ", ) );
function(menu) < var __t, __p = ''; __p += '

' + ((__t = (menu.title)) == null ? '' : __t) + '

'; return __p >

При таком подходе переменная title уже не будет искаться в объекте данных автоматически, поэтому нужно будет обращаться к ней как .

Кеширование скомпилированных шаблонов

Чтобы не компилировать один и тот же шаблон много раз, результаты обычно кешируют.

Например, глобальная функция getTemplate("menu-template") может доставать шаблон из HTML, компилировать, результат запоминать и сразу отдавать при последующих обращениях к тому же шаблону.

Меню на шаблонах

Рассмотрим для наглядности полный пример меню на шаблонах.

JS для создания меню:

var menu = new Menu(< title: "Сладости", // передаём также шаблоны template: _.template(document.getElementById('menu-template').innerHTML), listTemplate: _.template(document.getElementById('menu-list-template').innerHTML), items: [ "Торт", "Пончик", "Пирожное", "Шоколадка", "Мороженое" ] >); document.body.appendChild(menu.getElem());
function Menu(options) < var elem; function getElem() < if (!elem) render(); return elem; >function render() < var html = options.template(< title: options.title >); elem = document.createElement('div'); elem.innerHTML = html; elem = elem.firstElementChild; elem.onmousedown = function() < return false; >elem.onclick = function(event) < if (event.target.closest('.title')) < toggle(); >> > function renderItems() < if (elem.querySelector('ul')) return; var listHtml = options.listTemplate(< items: options.items >); elem.insertAdjacentHTML("beforeEnd", listHtml); > function open() < renderItems(); elem.classList.add('open'); >; function close() < elem.classList.remove('open'); >; function toggle() < if (elem.classList.contains('open')) close(); else open(); >; this.getElem = getElem; this.toggle = toggle; this.close = close; this.open = open; >

Здесь два шаблона. Первый мы уже разобрали, посмотрим теперь на список ul/li :

Если разбить шаблон для списка элементов по разделителям, то он будет таким:

Вот функция, которую возвратит _.template(tmpl) для этого шаблона:

    \n '; items.forEach(function(item) < __p += '\n
  • ' + __e(item) + // экранирование функцией _.escape '\n '; >); __p += '\n

Как видно, она один-в-один повторяет код и вставляет текст в переменную __p . При этом выражение в обёрнуто в вызов _.escape, который заменяет спецсимволы HTML на их текстовые варианты.

Отладка шаблонов

Что, если в шаблоне ошибка? Например, синтаксическая. Конечно, ошибки будут возникать, куда же без них.

Шаблон компилируется в функцию, ошибка будет либо при компиляции, либо позже, в процессе её выполнения. В различных шаблонных системах есть свои средства отладки, _.template тут не блистает.

Но и здесь можно кое-что отладить. При ошибке, если она не синтаксическая, отладчик при этом останавливается где-то посередине «страшной» функции.

Попробуйте сами запустить пример с открытыми инструментами разработчика и включённой опцией «остановка при ошибке»:

В шаблоне допущена ошибка, поэтому отладчик остановит выполнение.

В Chrome картина будет примерно такой:

Библиотека LoDash пытается нам помочь, подсказать, в каком именно шаблоне произошла ошибка. Ведь из функции это может быть неочевидно.

Для этого она добавляет к шаблонам специальный идентификатор sourceURL, который служит аналогом «имени файла». На картинке он отмечен красным.

По умолчанию sourceURL имеет вид /lodash/template/source[N] , где N – постоянно увеличивающийся номер шаблона. В данном случае мы можем понять, что эта функция получена при самой первой компиляции.

Это, конечно, лучше чем ничего, но, как правило, его имеет смысл заменить sourceURL на свой, указав при компиляции дополнительный параметр sourceURL :

. var compiled = _.template(tmpl, ); . 

Попробуйте запустить исправленный пример и вы увидите в качестве имени файла /template/menu-template .

Не определена переменная – ошибка

Кстати говоря, а в чём же здесь ошибка?

…А в том, что переменная items не передана в шаблон. При доступе к неизвестной переменной JavaScript генерирует ошибку.

Самый простой способ это обойти – обращаться к необязательным переменным через obj , например . Тогда в случае undefined просто ничего не будет выведено. Но в данном случае реакция совершенно адекватна, так как для меню список опций items является обязательным.

Итого

Шаблоны полезны для того, чтобы отделить HTML от кода. Это упрощает разработку и поддержку.

В этой главе подробно разобрана система шаблонизации из библиотеки LoDash:

  • Шаблон – это строка со специальными вставками кода или переменных , .
  • Вызов _.template(tmpl) превращает шаблон tmpl в функцию, которой в дальнейшем передаются данные – и она генерирует HTML с ними.

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

Шаблонных систем много. Многие основаны на схожем принципе – генерации функции из строки, например:

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

Такой подход используется во фреймворках:

Блог

Lodash - это неспецифическая библиотека программирования для JavaScript, которая в основном применяется для функционального программирования.

  • Работу с массивами, к примеру, получение определенного элемента в массиве, методы удаления элементов по определенному правилу, создание копии без дубликатов и многое другое.
  • Для работы с функциями в библиотеке присутствует множество методов для работы с контекстом, временем исполнением/вызова функции, и возможность определения композиции функций.
  • Для работы с объектами есть функции клонирования объектов и методы проверки значения объектов на принадлежность тому или иному типу.
  • Так же имеются функции работы со строками - удаление лишних пробелов, добавление заглавной буквы, вариации строчного/заглавного ввода, и многое другое.
  • Кроме коллекций, которые представляют из себя суперсеты массивов, есть еще секвенции, из которых удобно выстраивать последовательные обработчики коллекций или списков.
  • Lodash очень полезен, если вы собираетесь разрабатывать на нативном JavaScript, потому что она предоставляет множество удобных и полезных функций при совсем небольшом размере библиотеки - полный билд весит около 24 килобайтов. Если вы собираетесь разрабатывать в функциональной парадигме, хотите не бояться монад, и не любите заниматься изобретением велосипедов, вам стоит начать осваивать эту библиотеку.

Gradle - система сборки для Java, Kotlin и C++

Сегодня мы расскажем про систему сборки Gradle, которая широко используется, например, при сборке Java - приложений.

29 апреля 2021

Golang - востребованность и сферы применения

Сегодня мы решили рассказать, что из себя представляет язык программирования Golang - зачем он нужен, и как его можно использовать. Он был придуман в корпорации Google для того, чтобы разрабатывать быстрые и надежные бекенд – приложения (однако создан для того, чтобы писать, а не читать).

24 апреля 2021

Gihub Cli - классная надстройка на обычным Git

Всем привет! Сегодня мы решили рассказать вам про классную надстройку над стандартной Git, которую умеренно рекламирует Gihub – Github-CLI. Поговорим о том, какие у нее возможности, и кому она может быть интересна.

Полезные функции библиотеки Lodash

Lodash — это JavaScript библиотека, которая упрощает работу с массивами, числами, объектами, строками путём предоставления множества полезных методов.

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

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

Почему Lodash по-прежнему полезен?

С выпуском ES6 и более поздними версиями JavaScript появилось множество методов, расширяющих функциональность языка. Например, появились новые методы массивов и строк, а также такие полезные операторы, как spread и rest .

Однако такие служебные библиотеки, как Lodash, продолжают оставаться актуальными, так как содержат множество полезных методов, всё ещё не доступных в JavaScript из коробки.

В этой статье мы рассмотрим несколько методов из Lodash, которые по-прежнему делают разработку проще, чем чистый JavaScript: times , get , set , debounce , deburr и keyBy .

_.times

Метод times позволяет вызвать функцию несколько раз, помещает результат вызова каждой функции в массив и возвращает массив.

Метод принимает два аргумента: количество вызовов функции и саму функцию для вызова. Например:

import * as _ from "lodash";const getRandomInteger = () => Math.round(Math.random() * 100);
let result = _.times(5, getRandomInteger);
console.log(result);
[16, 83, 35, 87, 41]

_.debounce

Метод debounce используется для того, чтобы отложить вызов функции на определённое время. В JavaScript не существует простого способа сделать это.

Метод полезен для обработки событий, если мы хотим подождать, пока выполнится что-то, а затем вызвать функцию. Например, при поиске с ввода клавиатуры debounce будет ждать, пока пользователь закончит ввод, прежде чем вызвать API, удаляя ненужные обращения к серверу.

Например, учтём численный ввод:

Пишем следующий JavaScript код:

import * as _ from "lodash";const checkPositiveNumber = e => console.log(+e.target.value > 0);
>;
const numInput = document.querySelector("input[type=number]");
numInput.addEventListener("input", _.debounce(checkPositiveNumber, 600));

Он содержит функцию checkPositiveNumber , которая проверяет, является ли введённое значение положительным. Затем используем метод debounce , который принимает в качестве значений функцию и задержку вызова в миллисекундах.

Функция, которую возвращает debouce , имеет те же параметры, что и исходная функция, за исключением того, что её вызов задерживается на указанное время.

_.get

Метод get позволяет нам безопасным способом получить доступ к свойствам объекта. Даже если путь к свойствам не существует, метод вернёт undefined или значение по умолчанию вместо сбоя программы.

Например, дан следующий объект:

const obj = foo: bar: < baz: < a: 3 >>, 
foo: < b: 2 >,
baz: [1, 2, 3]
>
>;

Доступ к свойствам obj можно получить следующим образом:

const result = _.get(obj, "foo.bar.baz.a", 1);

Первый аргумент — это объект, к значению свойства которого мы хотим получить доступ. Второй — это путь к свойству. Последний аргумент — значение по умолчанию. Получим 3 в качестве result .

В то же время, если путь не существует или undefined , мы получим undefined или значение по умолчанию. Например, если у нас есть:

const result = _.get(obj, "foo.bar.a", 1);

Мы получим 1 в result . Если мы не зададим значение по умолчанию:

const result = _.get(obj, "foo.bar.a");

Получим undefined . Не существует способа безопасно получить значение глубоко вложенного свойства, пока оператор опциональной последовательности не станет основным.

_.set

Метод set нужен, чтобы задать значение свойству объекта. Например, дан тот же объект, что мы использовали выше:

const obj = foo: bar: < baz: < a: 3 >>, 
foo: < b: 2 >,
baz: [1, 2, 3]
>
>;

Задать значение свойства можно, написав:

_.set(obj, "foo.bar.a", 1);

Объект obj изменён. Как видим, метод может задавать значения для свойств, которые до этого не существовали. У исходного объекта не было foo.bar.a , он автоматически добавился после того, как было задано значение 1.

 "foo": "bar": "baz": "a": 3 
>,
"a": 1
>,
"foo": "b": 2
>,
"baz": [
1,
2,
3
]
>
>

Это работает, даже если вложенный объект не существует. Напишем:

_.set(obj, "foo.foofoo.bar.a.b", 1);
 "foo": "bar": "baz": "a": 3 
>
>,
"foo": "b": 2
>,
"baz": [
1,
2,
3
],
"foofoo": "bar": "a": "b": 1
>
>
>
>
>

_.deburr

Чтобы удалить надстрочные знаки у символов строки, используем метод deburr . Он принимает строку и возвращает новую, где символы с надстрочными знаками заменены на символы без них.

Например, строка “S’il vous plaît” :

const result = _.deburr("S'il vous plaît");

Превращается в "S’il vous plait" . У ‘i’ больше нет надстрочного знака.

_.keyBy

Метод keyBy принимает массив и имя свойства и возвращает объект со значением свойства в качестве ключей объекта. Например, у нас есть следующий массив:

const people = [ 
< name: "Joe", age: 20 >,
< name: "Jane", age: 18 >,
< name: "Mary", age: 20 >
];
const results = _.keyBy(people, "name");

Тогда results будет следующим:

 "Joe": "name": "Joe", 
"age": 20
>,
"Jane": "name": "Jane",
"age": 18
>,
"Mary": "name": "Mary",
"age": 20
>
>

Затем получим объект с именем 'Joe' , написав:

results['Joe']

В чистом JavaScript нет простого способа сделать это без написания нескольких строк кода.

Заключение

В Lodash есть множество полезных функций, простых аналогов которым нет в чистом JavaScript.

Метод times для многократного вызова функции в одной строке; debounce для возврата новой функции с той же сигнатурой и кодом, что у исходной, но вызов которой отложен на заданное в миллисекундах время.

Для безопасного доступа и установки значений свойств есть методы get и set , не вызывающие сбоя при попытке доступа к несуществующему пути свойства или возвращающие значение undefined . Также существует метод deburr для замены символов с надстрочными знаками символами без знаков.

И, наконец, метод keyBy для преобразования массива в объект, который содержит значение заданного свойства каждой записи в качестве ключей и запись со значением имени заданного свойства в качестве значения.

  • Да не нужен вам фреймворк JavaScript!
  • Создание тестового фреймворка JavaScript
  • Лучшие практики JavaScript — производительность

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *