- Rest/Spread Свойства
- Асинхронная итерация
- Promise.prototype.finally()
- Улучшения регулярных выражений
Rest/Spread Свойства
ES6 представил концепцию rest
элементов при работе с деструктуризацией массива:
const numbers = [1, 2, 3, 4, 5];
[first, second, ...others] = numbers;
и spread
элементов:
const numbers = [1, 2, 3, 4, 5];
const sum = (a, b, c, d, e) => a + b + c + d + e;
const sumOfNumbers = sum(...numbers);
rest это ...
слева от знака оператора присваивания; означает остальные элементы, а spread находится справа и означает распространение элементов.
ES2018 ввел то же самое, но для объектов.
Rest свойство
const { first, second, ...others } = {
first: 1,
second: 2,
third: 3,
fourth: 4,
fifth: 5
};
first; // 1
second; // 2
others; // { third: 3, fourth: 4, fifth: 5 }
Spread свойство
Свойство spread
позволяет создавать новый объект путем объединения свойств объекта, переданного после оператора распространения ...
:
const items = { first, second, ...others };
items; //{ first: 1, second: 2, third: 3, fourth: 4, fifth: 5 }
Асинхронная итерация
Новая конструкция for-await-of
позволяет нам вызывать асинхронные функции, которые возвращают промис (или массивы с кучей промисов) в цикле. Круто то, что цикл ожидает выполнение каждого промиса, прежде чем перейти к следующему циклу:
const promises = [
new Promise(resolve => resolve(1)),
new Promise(resolve => resolve(2)),
new Promise(resolve => resolve(3))
];
async function test1() {
for await (const obj of promises) {
console.log(obj);
}
}
test1(); // 1, 2, 3
Так как он использует await
, ты можешь использовать его только внутри async
функций, как обычный await
в async/await.
Promise.prototype.finally()
Когда промис выполнен успешно, он вызывает методы then()
один за другим. Если что-то не получается во время этого, методы then()
пропускаются и выполняется метод catch()
.
finally()
позволяет запускать любой код, независимо от успешного или неуспешного выполнения промиса:
fetch("https://api.github.com/users/oleksiimyzgin")
.then(res => res.json())
.then(data => console.log(data))
.catch(error => console.error(error))
.finally(() => console.log("finished"));
Улучшения регулярных выражений
Утверждения регулярных выражений lookbehind
Так выглядит lookahead
(опережающая проверка) ?=
(знак вопроса, равно): при опережающей проверке определяется строка, за которой следует определенная подстрока. Lookahead
«смотрит» вперед и соответственно ставится в конце регулярного выражения. В данном примере мы ищем строку ‘Script’, перед которой стоит ‘Java’.
/Java(?=Script)/
/Java(?=Script)/.test('Java Script is cool'); // false - стоит пробел
/Java(?=Script)/.test('JavaScript is cool'); // true
?!
выполняет обратную операцию, проверяя, если за строкой не следует определенная подстрока:
/Java(?!Script)/
/Java(?!Script)/.test('Java Script is cool'); // true - стоит пробел
/Java(?!Script)/.test('JavaScript is cool'); // false
lookbehind
или ретроспективная проверка - это новая функция, которая использует ?<=
(знак вопроса, знак меньше, равно) и «смотрит» назад для положительного утверждения. Так как lookbehind
«смотрит» назад, то она соответственно ставится в начале регулярного выражения. В данном примере мы ищем строку ‘Java’ за которой стоит ‘Script’.
/(?<=Java)Script/
/(?<=Java)Script/.test('Java Script is cool'); // false - стоит пробел
/(?<=Java)Script/.test('JavaScript is cool'); // true
Кроме того, ты можешь использовать ?<!
(знак вопроса, знак меньше, восклицательный знак), чтобы найти отрицательное утверждение.
/(?<!Java)Script/
/(?<!Java)Script/.test('Java Script is cool'); // true - стоит пробел
/(?<!Java)Script/.test('JavaScript is cool'); // false
Управляющая последовательность Unicode в \p{…}
и \P{…}
В шаблоне регулярного выражения ты можешь использовать: \d
для сопоставления с любой цифрой, \s
для сопоставления с любым символом, который не является пробелом, \w
для сопоставления с любым цифробуквенным символом включая нижнее подчеркивание т.д.
Новый функционал расширил концепцию всех символов Юникода, представив \p{}
и отрицательный \P{}
.
Любой символ Юникода имеет набор свойств. Например, Script
определяет семейство языков; ASCII
- это логическое значение, которое true
для символов ASCII, и так далее. Ты можешь поместить это свойство в фигурные скобки, и регулярное выражение проверит, верно ли это:
/^\p{ASCII}+$/u.test('abc') // ✅
/^\p{ASCII}+$/u.test('ABC@') // ✅
/^\p{ASCII}+$/u.test('ABC🙃') // ❌
ASCII_Hex_Digit
- другое логическое свойство, которое проверяет, содержит ли строка только допустимые шестнадцатеричные числа:
/^\p{ASCII_Hex_Digit}+$/u.test('0123456789ABCDEF') // ✅
/^\p{ASCII_Hex_Digit}+$/u.test('h') // ❌
Есть много других логических свойств, которые ты просто проверяешь добавляя их имя в фигурные скобки, включая Uppercase
, Lowercase
, White_Space
, Alphabetic
, Emoji
и другие:
/^\p{Lowercase}$/u.test('h') // ✅
/^\p{Uppercase}$/u.test('H') // ✅
/^\p{Emoji}+$/u.test('H') // ❌
/^\p{Emoji}+$/u.test('🙃🙃') // ✅
В дополнение к этим двоичным свойствам, ты можешь проверить соответствует ли любое из свойств символа Юникода, определенному значению. В этом примере я проверяю, написана ли строка на греческом или латинском алфавите:
/^\p{Script=Greek}+$/u.test('ελληνικά') //✅
/^\p{Script=Latin}+$/u.test('hey') //✅
Узнай больше обо всех свойствах, которые ты можешь использовать непосредственно в предложении.
Захват именованных групп в регулярных выражениях
В ES2018, захвату именованных групп может быть назначено имя, а не просто слот в массиве результатов:
// ДО
const re1 = /(\d{4})-(\d{2})-(\d{2})/;
const result1 = re1.exec("2019-04-10");
console.log(result1);
// ["2019-04-10", "2019", "04", "10", index: 0, input: "2019-04-10", groups: undefined]
// ПОСЛЕ (ECMAScript ES2018)
const re2 = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const result2 = re2.exec("2019-04-10");
console.log(result2);
// [ "2019-04-10", "2019", "04", "10", index: 0, input: "2019-04-10",
// groups: {year: "2019", month: "04", day: "10"} 👈🏻👈🏻👈🏻
// ]
// result2.groups.year === '2019';
// result2.groups.month === '04';
// result2.groups.day === '10';
Флаг s
для регулярных выражений
Флаг s
, сокращенный от single line, заставляет .
соответствовать также символам новой строки. Без этого точка соответствует обычному символу, но не новой строке:
const re3 = /hi.welcome/;
const re4 = /hi.welcome/s;
re3.test("hi\nwelcome"); // false
re4.test("hi\nwelcome"); // true
re4.dotAll; // true
re4.flags; // "s"