ES2016-2018
Обзор важных нововведений в версиях стандарта языка JavaScript 2016 — 2018 годов
ES2016
1) Array.prototype.includes() – проверяет наличие значения в массиве (включая NaN):
const arr = [1, 3, 5, NaN]; arr.includes(5); // true arr.includes(NaN); // true arr.indexOf(NaN); // -1
2) Возведение в степень двумя звёздочками:
// было const a = Math.pow(3, 5); // 243 // теперь ещё стало const b = 7**5; // 16807
ES2017
1) Object.values() – возвращает массив значений объекта:
const obj = {
a : 1,
b : 2,
c : 3
}
Object.values(obj); // [1, 2, 3]
2) Object.entries() – возвращает массив пар "ключ-значение" объекта:
const obj = {
a : 1,
b : 2,
c : 3
}
Object.values(obj); // [["a", 1], ["b", 2], ["c", 3]]
3) String.prototype.padStart(), String.prototype.padEnd() – методы добавления к началу/концу строки подстроки, чтобы общая длина строки достигала заданной:
const strs = ["123", "12345", "1234567"];
strs.map((elem) => {
console.log(elem.padStart(10, "-"));
})
// -------123
// -----12345
// ---1234567
const strs = ["98765", "9876", "987"];
strs.map((elem) => {
console.log(elem.padEnd(7, "0"));
})
// 9876500
// 9876000
// 9870000
4) Async/Await – синтаксический сахар для работы с промисами. Async-функция всегда возвращает промис, await объявляется внутри кода async-функции и останавливает выполнение нижеследующего кода, пока не вернётся значение:
// async всегда возвращает promise
async function f() {
return 1
}
f().then((res) => console.log(res)) // 1
// alert выполнится через 3 секунды
async function f() {
const promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("answer"), 3000)
});
return(await promise);
}
f().then((res) => alert(res));
// замена цепочки промисов на более понятные вызовы
new Promise(function(resolve, reject) {
setTimeout(() => resolve(1), 1000);
}).then(function(result) {
console.log(result);
return result * 3;
}).then((result) => {
console.log(result)
return new Promise((resolve, reject) => { // (*)
setTimeout(() => resolve(result * 2), 1000);
});
}).then(function(result) {
console.log(result);
return result
});
// async/await-синтаксис, с реальными fetch, а не с синтетическими таймаутами будет ещё изящнее
async function f() {
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve(1), 1000)
});
let result = await promise;
console.log(result);
result = result * 3;
console.log(result);
promise = new Promise((resolve, reject) => {
setTimeout(() => resolve(result * 2), 1000)
});
result = await promise;
console.log(result);
return result;
}
f();
// параллельное выполнение кода, ответ придёт через 5 секунд, а не 10
async function twice(a, b) {
[a, b] = await Promise.all([count(a), count(b)]);
return a+b;
}
function count(n) {
return new Promise(resolve => {setTimeout(() => {resolve(n*2)}, 5000)});
}
twice(4, 8).then(result => console.log(result))
// методы классов тоже могут быть асинхронными
class Timer {
async waitASecond() {
return await new Promise((resolve, reject) => {
setTimeout(() => resolve("answer"), 1000)
})
}
}
new Timer() .waitASecond() .then(alert);
ES2018
1) Операторы rest/spread. Оба обозначаются троеточием, первый используется для извлечения свойств из объекта, второй для создания:
// деструктурирование объекта
const {a, b, ...remaining} = {
a : 1,
b : 2,
c : 3,
d : 4
}
console.log(a); // 1
console.log(b); // 2
console.log(remaining); // {c: 3, d: 4}
// копирование объекта
const {...remaining} = {
x : 1,
y : [],
z : function() { return 1 }
}
console.log(remaining); // {x: 1, y: Array, z: ƒ}
// удаление ненужного свойства объекта
const {x, ...remaining} = {
x : 1,
y : "2",
z : "three"
}
console.log(remaining); // останется всё без ненужного свойства
// spread объединяет свойство объектов
const first = {
a : 1,
b : [2, 4, 6]
}
const second = {
с : "3",
d : function() {return 1}
}
const common = {...first, ...second}; // {a: 1, b: Array(3), с: "3", d: ƒ}
// при создании объекта с помощью spread свойства могут перезаписываться, если объявлять их после
const first = {
a : 1,
b : 2
}
const second = {...first, b : 3}; // {a: 1, b: 3}
// но сохраняются, если объявление было до
const first = {
a : 1,
b : 2
}
const second = {b : 3, ...first}; // {b: 2, a: 1}
2) Promise.finally() – вызывается в промисах после resolve и reject, независимо от их результата. Это позволяет вам избавиться от дубликации кода в обработчиках then() и catch():
new Promise((resolve, reject) => {
resolve(1)
})
.then((res) => {console.log(res)})
.catch((error) => {console.log(error)})
.finally(() => {
console.log("This is finally")
})
// 1, затем This is finally
new Promise((resolve, reject) => {
reject(5)
})
.then((res) => {console.log(res)})
.catch((error) => {console.log(error)})
.finally(() => {
console.log("This is finally")
})
// 5, затем This is finally
3) Асинхронная итерация for-await-of
const promises = [
new Promise((resolve, reject) => resolve(1)),
new Promise((resolve, reject) => resolve(2)),
new Promise((resolve, reject) => resolve(3))
]
async function f1() {
for (let i of promises) {
console.log(i)
}
}
async function f2() {
for await (let i of promises) {
console.log(i)
}
}
f1(); // Promise, Promise, Promise
f2(); // 1, 2, 3