Хабрахабр

[Перевод] Возможности современного JavaScript, о которых вы могли не знать

Главные возможности вроде async/await и прокси — это одно, но ещё каждый год идёт поток мелких поэтапных изменений, которые не попадают в моё поле зрения, поскольку всегда находится что-то более важное для изучения. Несмотря на то, что в последние семь лет я пишу на JavaScript почти каждый рабочий день, должен признаться, что уделяю мало внимания сообщениям о нововведениях от ES.

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

ES2015

Двоичные и восьмеричные литералы

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

Именно для таких случаев в ES6 добавили формат двоичных литералов: 0b. Всё это может потребовать большого количества работы по скрытию/объединению двоичных чисел; мне всегда казалось, что их зря упрятали в десятичные.

const binaryZero = 0b0;
const binaryOne = 0b1;
const binary255 = 0b11111111;
const binaryLong = 0b111101011101101;

Это сильно упрощает работу с двоичными флагами:

// Pizza toppings
const olives = 0b0001;
const ham = 0b0010;
const pineapple = 0b0100;
const artechoke = 0b1000; const pizza_ham_pineapple = pineapple | ham;
const pizza_four_seasons = olives | ham | artechoke;

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

Number.isNaN()

Не путать с window.isNaN(), это новый метод с гораздо более интуитивным поведением.

У классического isNaN есть несколько интересных хитростей:

isNaN(NaN) === true
isNaN(null) === false
isNaN(undefined) === true
isNaN() === true
isNaN(0/0) === true
isNaN('hello') === true

Что нам это даёт? Во-первых, ни один из этих параметров на самом деле не является NaN. Как обычно, проблема во всеми «любимом» свойстве JavaScript: приведении типов. Аргументы для window.isNaN приведены к числам с помощью функции Number.

Он раз и навсегда возвращает равенство аргументов, переданных ему и NaN. Эту проблему решает новый статический метод Number.isNaN(). Это абсолютно однозначно:

Number.isNaN(NaN) === true
Number.isNaN(null) === false
Number.isNaN(undefined) === false
Number.isNaN({}) === false
Number.isNaN(0/0) === false
Number.isNaN('hello') === false

Сигнатура: Number.isNaN : (value: any) => boolean

ES2016

Оператор возведение в степень

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

2**2 === 4
3**2 === 9
3**3 === 27

Странно, но я был уверен, что в JavaScript такое уже есть. Возможно, спутал с Python.

Array.prototype.includes()

Такое трудно было пропустить, но если в последние три года вы писали array.indexOf(x) !== -1, то возрадуйтесь новому методу includes:

[1, 2, 3].includes(2) === true
[1, 2, 3].includes(true) === false

includes использует алгоритм Same Value Zero, который почти идентичен проверке на строгое равенство (===), за исключением того, что может обрабатывать значения NaN. Этот алгоритм тоже сравнивает объекты по ссылкам, а не содержимому:

const object1 = {};
const object2 = {}; const array = [object1, 78, NaN]; array.includes(object1) === true
array.includes(object2) === false
array.includes(NaN) === true

includes может брать второй параметр, fromIndex, который позволяет вам предоставлять значение сдвига:

// positions 0 1 2 3 4
const array = [1, 1, 1, 2, 2]; array.includes(1, 2) === true
array.includes(1, 3) === false

Полезно.

Сигнатура: Array.prototype.includes : (match: any, offset?: Int) => boolean

ES2017

Разделяемые память и атомарные операции

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

За подробностями отправляю вас к этой статье: https://www.sitepen.com/blog/the-return-of-sharedarraybuffers-and-atomics/. Это две большие возможности с довольно сложными API, так что здесь я их описывать не будут. Еще не все браузеры поддерживают эти функции, но надеюсь, что в ближайшие пару лет ситуация улучшится.

ES2018

Золотая жила регулярных выражений

В ES2018 появилась целая россыпь новых возможностей регулярных выражений:

Lookbehind-сопоставления (сопоставление с предыдущими символами)

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

const regex = /(?<=\$)\d+/;
const text = 'This cost $400';
text.match(regex) === ['400']

Всё дело в новой lookbehind-группе, близнеце lookahead-групп:

Look ahead: (?=abc)
Look behind: (?<=abc) Look ahead negative: (?!abc)
Look behind negative: (?<!abc)

К сожалению, сегодня нельзя транспилировать новый lookbehind-синтаксис под старые браузеры, так что вполне возможно, какое-то время вы сможете использовать его только в Node.

Именованные группы захвата

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

const getNameParts = /(\w+)\s+(\w+)/g;
const name = "Weyland Smithers";
const subMatches = getNameParts.exec(name); subMatches[1] === 'Weyland'
subMatches[2] === 'Smithers'

А теперь есть синтаксис присвоения имён этим подвыборкам (или группам записи): внутри скобок в начале ставим ?<titlе>, если хотим присвоить группе имя:

const getNameParts = /(?<first>\w+)\s(?<last>\w+)/g;
const name = "Weyland Smithers";
const subMatches = getNameParts.exec(name); const {first, last} = subMatches.groups
first === 'Weyland'
last === 'Smithers'

К сожалению, сейчас это работает только в Chrome и Node.

Теперь точки могут отмечать новые строки

Нужно только проставлять флаг /s, например, /someRegex./s, /anotherRegex./sg.

ES2019

Array.prototype.flat() и flatMap()

Я был очень рад увидеть это в MDN.

Попросту говоря, flat() преобразует многомерный массив в одномерный на заданную максимальную глубину (depth):

const multiDimensional = [ [1, 2, 3], [4, 5, 6], [7,[8,9]]
]; multiDimensional.flat(2) === [1, 2, 3, 4, 5, 6, 7, 8, 9]

flatMap — это map, за которым идёт flat с глубиной 1. Это полезно, если нужно мапить функцию, которая возвращает массив, но при этом вам не нужно, чтобы результат представлял собой вложенную структуру данных:

const texts = ["Hello,", "today I", "will", "use FlatMap"]; // with a plain map
const mapped = texts.map(text => text.split(' '));
mapped === ['Hello', ['today', 'I'], 'will', ['use', 'FlatMap']]; // with flatmap
const flatMapped = texts.flatMap(text => text.split(' '));
flatMapped === ['Hello', 'today', 'I', 'will', 'use', 'FlatMap'];

Неограниченные перехваты

Теперь вы можете писать выражения try/catch без привязки к киданию ошибок:

try { // something throws
} catch { // don't have to do catch(e)
}

Кстати, перехваты, в которых вы не учитываете значение e, иногда называют обработкой исключений-покемонов. Потому что вы должны поймать их все!

Методы обрезки строковых значений

Незначительно, но приятно:

const padded = ' Hello world ';
padded.trimStart() === 'Hello world ';
padded.trimEnd() === ' Hello world';

Теги
Показать больше

Похожие статьи

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

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

Кнопка «Наверх»
Закрыть