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

в 12:39, , рубрики: es2018, ES6, es8, IT-стандарты, javascript, Блог компании Mail.Ru Group, никто не читает теги, Программирование, Разработка веб-сайтов

Возможности современного JavaScript, о которых вы могли не знать - 1

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

В этой статье я собрал возможности современного 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.

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

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

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

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

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

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';

Автор: Макс

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js