Перейти к содержимому

Как поставить обратные кавычки в js

  • автор:

Как поставить обратные кавычки в js

Создайте регулярное выражение для поиска строк в двойных кавычках «. » .

Важно, что строки должны поддерживать экранирование с помощью обратного слеша, по аналогии со строками JavaScript. Например, кавычки могут быть вставлены как \» , новая строка как \n , а сам обратный слеш как \\ .

let str = "Как вот \"здесь\".";

В частности, обратите внимание: двойная кавычка после обратного слеша \» не оканчивает строку.

Поэтому мы должны искать от одной кавычки до другой, игнорируя встречающиеся экранированные кавычки.

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

Примеры подходящих строк:

.. "test me" .. .. "Скажи \"Привет\"!" . (строка с экранированными кавычками) .. "\\" .. (внутри двойной слеш) .. "\\ \"" .. (внутри двойной слеш и экранированная кавычка)

В JavaScript приходится удваивать обратные слеши, чтобы добавлять их в строку, как здесь:

let str = ' .. "test me" .. "Скажи \\"Привет\\"!" .. "\\\\ \\"" .. '; // эта строка в памяти: alert(str); // .. "test me" .. "Скажи \"Привет\"!" .. "\\ \"" ..
  • Сначала ищем открывающую кавычку «
  • Затем, если есть обратный слеш \\ (удвоение обратного слеша – техническое, потому что это спец.символ, на самом деле там один обратный слеш), то после него также подойдёт любой символ (точка).
  • Иначе берём любой символ, кроме кавычек (которые будут означать конец строки) и обратного слеша (чтобы предотвратить одинокие обратные слеши, сам по себе единственный обратный слеш не нужен, он должен экранировать какой-то символ) [^»\\]
  • …И так далее, до закрывающей кавычки.
let regexp = /"(\\.|[^"\\])*"/g; let str = ' .. "test me" .. "Скажи \\"Привет\\"!" .. "\\\\ \\"" .. '; alert( str.match(regexp) ); // "test me","Скажи \"Привет\"!","\\ \""

Одинарные, двойные и обратные кавычки в JavaScript

Перевод статьи «The real difference between ‘single quotes’ and “double quotes” in JavaScript».

Какие кавычки стоит использовать в JavaScript: одинарные или двойные? Ответ меня удивил: эти варианты совершенно идентичны, если не рассматривать вопрос экранирования.

«В JavaScript одинарные и двойные кавычки ведут себя совершенно одинаково», — пишет Мэтью Холман в своей статье на cloudboost.io.

И одинарные, и двойные кавычки в коде на JS используются довольно часто. С их помощью создаются строковые литералы.

«Литерал» — это просто еще одно слово, которым обозначается значение переменной (в то время как имя переменной — это ссылка).

Единственная разница между одинарными и двойными кавычками в JS связана с экранированием кавычек внутри строковых литералов.

Одинарные кавычки

Если строковый литерал образован при помощи одинарных кавычек ( » ), другие одинарные кавычки внутри него нужно экранировать при помощи обратного слэша ( \’ ).

const wittyAI = 'I am \'not\' sentient.' const wittyReply = 'No, you\'re definitely not "sentient."' console.log(wittyAI,wittyReply)

Двойные кавычки

Аналогично, если строковый литерал образован при помощи двойных кавычек ( «» ), другие двойные кавычки внутри него тоже нужно экранировать при помощи обратного слэша ( \’ ).

const _wittyAI = "I think therefore I 'am' -- sentient." const _wittyReply = "No, you only \"think\", so you aren't." console.log(_wittyAI,_wittyReply)

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

«Empty» === ‘Empty’

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

const empty = "" const alsoEmpty = '' console.log(empty === alsoEmpty) // true (both are empty string) console.log(empty.length) // 0 console.log(empty === false) // false console.log(empty === 0) // false console.log(empty == false) // true (falsy comparison) console.log(empty == 0) // true (falsy comparison)

Не лучше ли использовать обратные кавычки?

В ES6 появились шаблонные литералы, которые создаются при помощи обратных кавычек ( « ).

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

Эти литералы имеют три больших преимущества:

1. Более простая конкатенация («интерполяция переменных»)

"string "+variable превращается в `string $`

2. Отпадает необходимость экранировать одинарные или двойные кавычки

"\"Hello World!\"" превращается в `"Hello World"`

3. Многострочный код можно писать без символов новой строки (\n)

"Hello\nWorld!" превращается в `Hello World`

Обратные кавычки также больше подходят для HTML:

const webAwareAI = ` 

Loading consciousness. It's loading.

` console.log(webAwareAI) /** * Output: *
*

Loading consciousness. It's loading.

*
*/

Шаблонные литералы не уступают по скорости строковым. Так почему бы не использовать повсеместно обратные кавычки?

Не забывайте о JSON

Легковесный формат хранения данных JSON допускает использование только двойных кавычек.

Если мне нужно постоянно копировать код из JavaScript в файлы JSON и обратно, использование двойных кавычек поможет поддерживать единообразие. Это случается довольно редко, так что мне приходится напоминать себе не использовать одинарные кавычки в JSON.

Функции stringify() и parse() , которые используются для работы с файлами JSON внутри JavaScript, знают о двойных кавычках:

const greetings = JSON.stringify() console.log(greetings) // console.log(JSON.parse(greetings)) // Object < Hello: "World!" >// JSON requires double quotes: JSON.parse("") // Object < Hello: "World!" >JSON.parse(``) // Object < Hello: "World!" >try < JSON.parse("") > catch(e) < console.log(e) >// SyntaxError: JSON.parse: expected property name or '>' at line 1 column 2 of the JSON data try < JSON.parse("") > catch(e) < console.log(e) >// SyntaxError: JSON.parse: unexpected character at line 1 column 10 of the JSON data

Как видно из примера, одинарные кавычки мешают распарсить JSON.

С технической точки зрения причина этого — в спецификации JSON (RFC 7159), где есть требование использования именно двойных кавычек.

Почему бы не использовать все три вида кавычек?

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

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

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

// bad const name = "Capt. Janeway"; // bad - template literals should contain interpolation or newlines const name = `Capt. Janeway`; // good const name = 'Capt. Janeway';

Для обеспечения единообразия используйте ESLint

Если последовательность стиля имеет для вас значение (как и для разработчиков Airbnb), ее легко обеспечить при помощи ESLint:

  • Правило quotes в ESLint может требовать использования двойных кавычек (по умолчанию), а одинарных или обратных — там, где это возможно.
  • Это правило также может требовать применения только одного вида кавычек. (За исключением случаев, если строка содержит символ кавычки, который придется экранировать).
  • Наконец, ESLint может требовать использования одинарных или двойных кавычек и при этом допускать использование обратных для создания шаблонных литералов.

Используйте Prettier и вообще забудьте об этой проблеме

Более простое решение, чем использовать ESLint для обеспечения единообразия стиля, — использовать Prettier для автоматического форматирования.

В Prettier по умолчанию используются двойные кавычки. Но его можно легко переключить на использование одинарных (по крайней мере, в CodeSandbox.io).

Для Prettier также есть соответствующее расширение в VSCode.

Мои личные предпочтения

В своем коде я склонен использовать двойные и обратные кавычки, хотя подумываю об использовании исключительно обратных.

Prettier я использую с дефолтными установками для двойных кавычек — просто привык к этому.

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

Но если придется выбирать, думаю, стоит остановиться на обратных кавычках, поскольку шаблонные литералы имеют преимущества вроде интерполяции и многострочности.

Строки

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

Есть ряд улучшений и новых методов для строк.

Начнём с, пожалуй, самого важного.

Строки-шаблоны

Добавлен новый вид кавычек для строк:

let str = `обратные кавычки`;

Основные отличия от двойных «…» и одинарных ‘…’ кавычек:

    В них разрешён перевод строки. Например:

alert(`моя многострочная строка`);
'use strict'; let apples = 2; let oranges = 3; alert(`$ + $ = $`); // 2 + 3 = 5

Функции шаблонизации

Можно использовать свою функцию шаблонизации для строк.

Название этой функции ставится перед первой обратной кавычкой:

let str = func`моя строка`;

Эта функция будет автоматически вызвана и получит в качестве аргументов строку, разбитую по вхождениям параметров $ и сами эти параметры.

'use strict'; function f(strings, . values) < alert(JSON.stringify(strings)); // ["Sum of "," + "," =\n ","!"] alert(JSON.stringify(strings.raw)); // ["Sum of "," + "," =\\n ","!"] alert(JSON.stringify(values)); // [3,5,8] >let apples = 3; let oranges = 5; // | s[0] | v[0] |s[1]| v[1] |s[2] | v[2] |s[3] let str = f`Sum of $ + $ =\n $!`;

В примере выше видно, что строка разбивается по очереди на части: «кусок строки» – «параметр» – «кусок строки» – «параметр».

  • Участки строки идут в первый аргумент-массив strings .
  • У этого массива есть дополнительное свойство strings.raw . В нём находятся строки в точности как в оригинале. Это влияет на спец-символы, например в strings символ \n – это перевод строки, а в strings.raw – это именно два символа \n .
  • Дальнейший список аргументов функции шаблонизации – это значения выражений в $ , в данном случае их три.

Зачем strings.raw ?

В отличие от strings , в strings.raw содержатся участки строки в «изначально введённом» виде.

То есть, если в строке находится \n или \u1234 или другое особое сочетание символов, то оно таким и останется.

Это нужно в тех случаях, когда функция шаблонизации хочет произвести обработку полностью самостоятельно (свои спец. символы?). Или же когда обработка спец. символов не нужна – например, строка содержит «обычный текст», набранный непрограммистом без учёта спец. символов.

Как видно, функция имеет доступ ко всему: к выражениям, к участкам текста и даже, через strings.raw – к оригинально введённому тексту без учёта стандартных спец. символов.

Функция шаблонизации может как-то преобразовать строку и вернуть новый результат.

В простейшем случае можно просто «склеить» полученные фрагменты в строку:

'use strict'; // str восстанавливает строку function str(strings, . values) < let str = ""; for(let i=0; i// последний кусок строки str += strings[strings.length-1]; return str; > let apples = 3; let oranges = 5; // Sum of 3 + 5 = 8! alert( str`Sum of $ + $ = $!`);

Функция str в примере выше делает то же самое, что обычные обратные кавычки. Но, конечно, можно пойти намного дальше. Например, генерировать из HTML-строки DOM-узлы (функции шаблонизации не обязательно возвращать именно строку).

Или можно реализовать интернационализацию. В примере ниже функция i18n осуществляет перевод строки.

Она подбирает по строке вида «Hello, $!» шаблон перевода «Привет, !» (где – место для вставки параметра) и возвращает переведённый результат со вставленным именем name :

'use strict'; let messages = < "Hello, !": "Привет, !" >; function i18n(strings, . values) < // По форме строки получим шаблон для поиска в messages // На месте каждого из значений будет его номер: , , … let pattern = ""; for(let i=0; i'; > pattern += strings[strings.length-1]; // Теперь pattern = "Hello, !" let translated = messages[pattern]; // "Привет, !" // Заменит в "Привет, " цифры вида на values[num] return translated.replace(/\/g, (s, num) => values[num]); > // Пример использования let name = "Вася"; // Перевести строку alert( i18n`Hello, $!` ); // Привет, Вася!

Итоговое использование выглядит довольно красиво, не правда ли?

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

Улучшена поддержка Юникода

Внутренняя кодировка строк в JavaScript – это UTF-16, то есть под каждый символ отводится ровно два байта.

Но под всевозможные символы всех языков мира 2 байт не хватает. Поэтому бывает так, что одному символу языка соответствует два Юникодных символа (итого 4 байта). Такое сочетание называют «суррогатной парой».

Самый частый пример суррогатной пары, который можно встретить в литературе – это китайские иероглифы.

Заметим, однако, что не всякий китайский иероглиф – суррогатная пара. Существенная часть «основного» Юникод-диапазона как раз отдана под китайский язык, поэтому некоторые иероглифы – которые в неё «влезли» – представляются одним Юникод-символом, а те, которые не поместились (реже используемые) – двумя.

alert( '我'.length ); // 1 alert( '��'.length ); // 2

В тексте выше для первого иероглифа есть отдельный Юникод-символ, и поэтому длина строки 1 , а для второго используется суррогатная пара. Соответственно, длина – 2 .

Китайскими иероглифами суррогатные пары, естественно, не ограничиваются.

Ими представлены редкие математические символы, а также некоторые символы для эмоций, к примеру:

alert( '��'.length ); // 2, MATHEMATICAL SCRIPT CAPITAL X alert( '��'.length ); // 2, FACE WITH TEARS OF JOY

В современный JavaScript добавлены методы String.fromCodePoint и str.codePointAt – аналоги String.fromCharCode и str.charCodeAt , корректно работающие с суррогатными парами.

Например, charCodeAt считает суррогатную пару двумя разными символами и возвращает код каждой:

// как будто в строке два разных символа (на самом деле один) alert( '��'.charCodeAt(0) + ' ' + '��'.charCodeAt(1) ); // 55349 56499

…В то время как codePointAt возвращает его Unicode-код суррогатной пары правильно:

// один символ с "длинным" (более 2 байт) unicode-кодом alert( '��'.codePointAt(0) ); // 119987

Метод String.fromCodePoint(code) корректно создаёт строку из «длинного кода», в отличие от старого String.fromCharCode(code) .

// Правильно alert( String.fromCodePoint(119987) ); // �� // Неверно! alert( String.fromCharCode(119987) ); // 풳

Более старый метод fromCharCode в последней строке дал неверный результат, так как он берёт только первые два байта от числа 119987 и создаёт символ из них, а остальные отбрасывает.

\u

Есть и ещё синтаксическое улучшение для больших Unicode-кодов.

В JavaScript-строках давно можно вставлять символы по Unicode-коду, вот так:

alert( "\u2033" ); // ″, символ двойного штриха

Синтаксис: \uNNNN , где NNNN – четырёхзначный шестнадцатиричный код, причём он должен быть ровно четырёхзначным.

«Лишние» цифры уже не войдут в код, например:

alert( "\u20331" ); // Два символа: символ двойного штриха ″, а затем 1

Чтобы вводить более длинные коды символов, добавили запись \u , где NNNNNNNN – максимально восьмизначный (но можно и меньше цифр) код.

alert( "\u" ); // ��, китайский иероглиф с этим кодом

Unicode-нормализация

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

Например, на основе обычного символа a существуют символы: àáâäãåā . Самые часто встречающиеся подобные сочетания имеют отдельный Юникодный код. Но отнюдь не все.

Для генерации произвольных сочетаний используются несколько Юникодных символов: основа и один или несколько значков.

Например, если после символа S идёт символ «точка сверху» (код \u0307 ), то показано это будет как «S с точкой сверху» Ṡ .

Если нужен ещё значок над той же буквой (или под ней) – без проблем. Просто добавляем соответствующий символ.

К примеру, если добавить символ «точка снизу» (код \u0323 ), то будет «S с двумя точками сверху и снизу» Ṩ .

Пример этого символа в JavaScript-строке:

alert("S\u0307\u0323"); // Ṩ

Такая возможность добавить произвольной букве нужные значки, с одной стороны, необходима, а с другой стороны – возникает проблемка: можно представить одинаковый с точки зрения визуального отображения и интерпретации символ – разными сочетаниями Unicode-кодов.

alert("S\u0307\u0323"); // Ṩ alert("S\u0323\u0307"); // Ṩ alert( "S\u0307\u0323" == "S\u0323\u0307" ); // false

В первой строке после основы S идёт сначала значок «верхняя точка», а потом – нижняя, во второй – наоборот. По кодам строки не равны друг другу. Но символ задают один и тот же.

С целью разрешить эту ситуацию, существует Юникодная нормализация, при которой строки приводятся к единому, «нормальному», виду.

В современном JavaScript это делает метод str.normalize().

alert( "S\u0307\u0323".normalize() == "S\u0323\u0307".normalize() ); // true

Забавно, что в данной конкретной ситуации normalize() приведёт последовательность из трёх символов к одному: \u1e68 (S с двумя точками).

alert( "S\u0307\u0323".normalize().length ); // 1, нормализовало в один символ alert( "S\u0307\u0323".normalize() == "\u1e68" ); // true

Это, конечно, не всегда так, просто в данном случае оказалось, что именно такой символ в Юникоде уже есть. Если добавить значков, то нормализация уже даст несколько символов.

Для большинства практических задач информации, данной выше, должно быть вполне достаточно, но если хочется более подробно ознакомиться с вариантами и правилами нормализации – они описаны в приложении к стандарту Юникод Unicode Normalization Forms.

Полезные методы

Добавлен ряд полезных методов общего назначения:

  • str.includes(s) – проверяет, включает ли одна строка в себя другую, возвращает true/false .
  • str.endsWith(s) – возвращает true , если строка str заканчивается подстрокой s .
  • str.startsWith(s) – возвращает true , если строка str начинается со строки s .
  • str.repeat(times) – повторяет строку str times раз.

Конечно, всё это можно было сделать при помощи других встроенных методов, но новые методы более удобны.

Итого

  • Строки-шаблоны – для удобного задания строк (многострочных, с переменными), плюс возможность использовать функцию шаблонизации для самостоятельного форматирования.
  • Юникод – улучшена работа с суррогатными парами.
  • Полезные методы для проверок вхождения одной строки в другую.

ES6 в деталях: шаблонные строки

На прошлой неделе я обещал сбавить темп. Я говорил, что после итераторов и генераторов мы возьмёмся за что-нибудь полегче, что-то, что не вынесет вам мозг. Посмотрим, смогу ли сдержать своё обещание.

А пока начнём с чего-нибудь простого.

Обратные кавычки

В ES6 появился новый вид синтаксиса строкового литерала под названием шаблонные строки. Они выглядят как обычные строки за исключением того, что обёрнуты символами обратных кавычек ` вместо обычных кавычек ‘ или » . И в простейшем случае это действительно всего лишь строки.

context.fillText(`Ceci n'est pas une chaîne.`, x, y); 

Но они неспроста называются «шаблонные строки», а не «старые и скучные ничем не примечательные обыкновенные строки, но только с обратными кавычками». Вместе с шаблонными строками в JavaScript появляется простая строковая интерполяция. Иными словами, это способ опрятно и удобно подставлять значения JavaScript в строки.

Их можно применять в миллионах случаев, но моё сердце греет такое скромное сообщение об ошибке:

function authorize(user, action) < if (!user.hasPrivilege(action)) < throw new Error( `Пользователю $ не разрешено $ .`); > > 

В этом примере $ and $ называются шаблонными подстановками. JavaScript вставит значения user.name и action в получившуюся строку. Так можно сгенерировать сообщение вроде Пользователю jorendorff не разрешено играть в хоккей. (Что между прочим, правда. У меня нет хоккейной лицензии.)

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

  • Код в шаблонной подстановке может быть любым выражением JavaScript, так что вызовы функций, арифметика и т.п. разрешены. (Если вы действительно хотите, то можете поместить в шаблонной строке другую шаблонную строку, я это называю шаблонным Началом.)
  • Если какое-то значение не строкового типа, оно будет приведено к строке при помощи обычных правил. К примеру, если action — объект, у него вызовется метод .toString() .
  • Если вам нужно использовать символ обратной кавычки в шаблонной строке, её нужно экранировать обратным слэшем: `\« — это то же самое, что «`» .
  • Точно так же, если вам нужно указать в шаблонной строке два символа $ < , я не знаю зачем вам это может понадобиться, но вы можете экранировать любой из символов обратным слэшем: `пишите \$< или $\

В отличие от обычных строк, в шаблонных строках можно использовать символы переноса строк:

$("#warning").html(` h1>Внимание! h1> p>Несанкционированная игра в хоккей может повлечь пенальти на срок до $ минут. p> `); 

Все пробельные символы в шаблонной строке, включая переносы строк и отступы, включаются «как есть» в результат.

Хорошо. Из-за того, что я пообещал на прошлой неделе, я чувствую свою ответственность за сохранность вашего мозга. Можете прекратить читать прямо сейчас, возможно, пойти выпить чашечку кофе и насладиться своим невредимым мозгом, который все еще находится в вашей черепной коробке. Серьёзно, нет ничего постыдного в том, чтобы отступить. Разве Лопес Гонсальвес ринулся целиком исследовать южное полушарие после того, как доказал, что суда могут пересекать экватор не будучи разбитыми морскими чудищами и не падая с края Земли? Нет. Он повернул обратно домой и хорошенько пообедал. Вам же нравится обедать, верно?

С обратными кавычками в будущее

Давайте поговорим немного о том, чего шаблонные строки не делают.

  • Они не экранируют автоматически спецсимволы. Чтобы избегать уязвимостей межсайтового скриптинга, вам всё ещё нужно обращаться с ненадёжными данными с осторожностью, точно так же, как при конкатенации обычных строк.
  • Неочевидно, как они должны работать с библиотекой интернационализации (эта библиотека позволяет вашему коду разговаривать на разных языках с разными пользователями). Шаблонные строки не поддерживают форматирование чисел и дат в зависимости от языка, и даже не помогут с плюрализацией.
  • Они не замена библиотекам-шаблонизаторам вроде Mustache или Nunjucks. Шаблонные строки не обладают каким-либо встроенным синтаксисом для циклов, например для генерации строк таблицы из массива. В них нет даже условных операторов. (Да, вы можете воспользоваться шаблонным Началом для этих целей, но мне кажется, что такое стоит делать разве что ради прикола.)

У шаблонных строк в ES6 есть ещё один козырь, который позволяет программистам и разработчикам библиотек не только обойти эти ограничения, но ещё и много чего другого. То, о чём я говорю, называется помеченными шаблонами.

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

Обратите внимание, SaferHTML — это не что-то, что предоставляется стандартной библиотекой. Сейчас мы напишем её сами.

var message = SaferHTML`

$ отвесил вам леща.

`
;

В качестве метки здесь выступает одиночный идентификатор SaferHTML , но меткой также может быть свойство, например SaferHTML.escape , или даже вызов метода, например SaferHTML.escape() . (Если быть совсем точным, любое выражение MemberExpression или CallExpression может быть тегом.)

Мы видели, что шаблонные строки без меток — это краткий способ простой строковой конкатенации. Помеченные шаблоны — это нечто совсем другое, вызов функции.

Код выше эквивалентен такому:

var message = SaferHTML(templateData, bonk.sender); 

где templateData — это неизменяемый массив всех частей строки в шаблоне, созданный движком JS. В нашем случае в массиве будет два элемента, потому что в помеченной шаблонной строке две части, разделённых подстановкой. Так что templateData будет Object.freeze ([«

«, » отвесил вам леща.

«])

(На самом деле, в templateData есть ещё одно свойство, templateData.raw — это другой массив, содержащий все строковые части шаблона, но на этот раз они в точности в таком виде, в каком они были в исходном коде. Экранирующие последовательности вроде \n оставлены в них как есть, вместо того, чтобы превратиться в перевод каретки, ну и тому подобное. Стандартная метка String.raw использует эти сырые строки.)

Это даёт функции SaferHTML свободу интерпретировать как строку, так и подстановки миллионом различных способов.

Прежде чем продолжить чтение, может быть вы захотите попробовать разобраться в том, что SaferHTML должна делать и попробуете вручную её реализовать? В конце концов, это же всего лишь обычная функция. Мы можете проверять, что у вас получается, в консоли разработчика в Firefox.

Вот одно из возможных решений (также доступное как gist).

function SaferHTML(templateData) < var s = templateData[0]; for (var i = 1; i < arguments.length; i++) < var arg = String(arguments[i]); // Экранируем спецсимволы в подстановках. s += arg.replace(/&/g, "&") .replace(/, "<") .replace(/>/g, ">"); // Не экранируем спецсимволы в шаблоне. s += templateData[i]; > return s; > 

В таком определении помеченный шаблон SaferHTML`

$ отвесил вам леща.

` может развернуться в строку «

ES6<3er отвесил вам леща.

» . Ваши пользователи в безопасности даже если пользователь со зловредным именем вроде Хакер Стив отвесит им леща. Что бы это ни значило.

(Кстати, если такой способ использования функцией объекта arguments кажется вам неуклюжим, заходите на следующей неделе. В ES6 есть ещё одна фича, которая, думаю, вам понравится.)

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

  • Шаблонные строки не экранируют спецсимволы автоматически. Но, как мы увидели, с помеченными шаблонами вы можете исправить это дело самостоятельно, написав метку. Вообще говоря, можно делать даже намного лучше. С точки зрения безопасности моя функция SaferHTML достаточно слабая. В разных местах HTML есть разные спецсимволы, которые нужно по-разному экранировать, и SaferHTML экранирует не все из них. Но приложив небольшое усилие вы могли бы написать намного более умную функцию SaferHTML , которая разбирает куски HTML в строках из массива templateData , чтобы узнать, какие подстановки в простом HTML; какие из них внутри атрибутов и требуют ещё и экранирования ‘ и » ; какие в строке запроса в URL и должны экранироваться как в URL, а не как в HTML; ну и так далее. Она могла бы применять нужное экранирование к каждой подстановке. Вам кажется, что это оторвано от реальности, потому что разбор HTML медленный? К счастью, строковые части помеченного шаблона не меняются, когда шаблон вычисляется повторно. SaferHTML могла бы кэшировать результаты этого разбора для ускорения будущих вызовов. (Этим кэшем может быть WeakMap, другая функциональность ES6, которую мы обсудим в будущих статьях.)
  • У шаблонных строк нет встроенных средств для интернационализации. Но с метками мы можем их добавить. Статья Джека Хсу (Jack Hsu) демонстрирует первые шаги к тому, как это будет выглядеть. Один пример для привлечения внимания:

i18n`Hello $ , you have $ :c(CAD) in your bank account.` // => Привет, Боб, у вас 1 234,56 канадских долларов на банковском счёте. 
// Чисто гипотетический язык шаблонизатора, основанный // на помеченных шаблонах ES6. var libraryHtml = hashTemplate` ul> #for book in $ li>i># i> от # li> #end ul> `; 

Гибкость этим не ограничивается. Заметьте, что аргументы функции-метки не приводятся автоматически к строкам. Они могут быть чем угодно. То же самое касается и возвращаемого значения. Помеченные шаблоны даже не обязательно должны быть строками! Вы можете использовать собственные метки, чтобы создавать регулярки, деревья DOM, изображения, промисы над целыми асинхронными процессами, структуры данных JS, шейдеры GL…

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

Когда можно начинать этим пользоваться?

На сервере шаблонные строки поддерживаются в io.js уже сегодня.

Из браузеров их поддерживает Firefox 34+. В Chrome поддержка зависит от настройки «Экспериментальный JavaScript», которая по умолчанию выключена. Пока что, если вы хотите применять шаблонные строки в вебе, нужно пользоваться Babel или Traceur. Вы также можете использовать их прямо сейчас в TypeScript!

Подождите! А что насчёт Markdown?

Ой. …Хороший вопрос.

(Этот раздел не про JavaScript. Если вы не пользуетесь Markdown, можете смело его пропускать.)

С появлением шаблонных строк выходит, что и Markdown и JavaScript теперь используют один и тот же символ ` для обозначения чего-то особенного. Фактически, в Markdown это разделитель кусков кода посреди обычного текста.

А вот тут небольшая проблема! Если вы напишете в документе Markdown так:

Чтобы показать сообщение, напишите `alert(`hello world!`)`. 

то оно отобразится как:

Чтобы показать сообщение, напишите alert( hello world! ) .

Заметьте, на выходе нет обратных кавычек. Markdown интерпретировал все четыре обратные кавычки как разделители кода и заменил их на теги HTML.

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

Чтобы показать сообщение, напишите ``alert(`hello world!`)``. 

В этом Gist все подробности на эту тему, и он написан на Markdown, так что вы можете посмотреть на исходник.

Что дальше

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

Мы посмотрим на них глазами человека, который реализовал их в Firefox. Так что пожалуйста присоединяйтесь к нам на следующей неделе, и наш приглашённый автор Бенджамин Петерсон (Benjamin Peterson) представит в деталях параметры по умолчанию и остаточные параметры из ES6.

© 2013 Frontender Magazine

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

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