Modern JavaScript: ТОП-3 синтаксических конструкций современного JS
Самые крутые синтаксические конструкции JavaScript по версии месье Томинова и авторский обзор.
JavaScript развивается стремительными темпами, в язык постоянно добавляются новые возможности. Кажется, ещё вчера JS считали жалкой игрушкой верстальщиков для наворачивания простых скриптов в вёрстке.
Пожалуй, так оно и было — язык с кучей проблем совместимости браузеров, "непонятным" ООП на прототипах, всплытием переменных и странным this. Самая крутая библиотека — jQuery, а самое крутое приложение — почтовый веб клиент от Гугл.
Однако, времена меняются и сегодня JavaScript используется как для построения сложных web–интерфейсов, так и во многих других сферах, начиная с утилит автоматизации и до серверного node.js.
Предлагаю к рассмотрению 3 самые удачные, по мнению автора, синтаксические конструкции в современном JS.
№1 Стрелочные лямбда функции
() => {}, () => ()
Лямбды, или анонимные функции появились сравнительно давно, однако это та часть синтаксиса, которая лично меня повергла в настоящий восторг, когда я впервые о ней узнал 🔥
Изначально, пришли они к нам из CoffeeScript (помните такой? 😉), где именовались не иначе как fat-arrow-functions.
Основная фича таких функций — отсутствие собственного контекста.
// arrow-function: самая обычная функция:
square = num -> num * num // -> function square (num) { return num * num }
// fat-arrow-function: функция с замыканием контекста:
Something = () ->
@fired = false // то же что this.fired = false
setTimeout () =>
@fired = true
, 1000
// получаем что-то вроде
function Something () {
this.fired = false
// замыкаем контекст с помощью IIFE
setTimeout((function (_this) {
_this.fired = true
})(this), 1000)
}
Конечно, во времена первых версий CoffeeScript, контекст у таких функций не отсутствовал, а подменялся родительским, что можно заметить в результате компиляции.
Сегодняшние стрелочные функции позволяют получить подобное поведение в ванильном JavaScript, без необходимости использования каких либо надмножеств языка и прекомпиляции кода и с честным отсутствием контекста.
Вот небольшой пример, как это выглядит на JavaScript:
/*
Как писали до появления стрелочных функций
*/
this.methodName = function () {
// сохраняем ссылку на текущий контекст в переменной self
var self = this
setInterval(function () {
self.innerText = ++self._elapsedSeconds
}, 1000)
}
/*
Используем стрелочные функции
*/
this.methodName = function () {
setInterval(() => {
this.innerText = ++this._elapsedSeconds
}, 1000)
}
Отсутствие контекста вносит свои ограничения для этих функций:
- Нет поддержки объекта arguments
- Не применимы для функций связывания контекста, врод call, apply, bind
- Не могут использоваться как функции конструкторы
- Не могут быть функциями–генераторами
Синтаксис стрелочных функций позволяет также не использовать в ряде случаев ключевое слово return для возвращения значений.
Таким образом мы можем возвращать результат вычислений на месте:
(a, b) => a + b — эквивалентно (a, b) => { return a + b }
Однако в случае когда функция должна вернуть объектный литерал, нужно воспользоваться одним из этих способов:
() => { return { a: 'b' } } — тут всё понятно
() => ({ a: 'b' }) ← обратите внимание на оборачивающие скобки
Как видите, стрелочные функции позволяют не только писать более короткий код, но и более производительный, ведь такая функция занимает гораздо меньше ресурсов за счёт отсутствия собственного контекста.
№2 Деструктуризация
const [ x ] = [ a, b, c ]
Эта синтаксическая конструкция позволяет легко извлекать данные из массивов и объектных литералов. В примере выше вытаскивается первый элемент массива и сохраняется в переменную x.
При этом операция не мутирующая, т.е. исходный массив после извлечения не изменяется.
Помимо извлечения из массивов, деструктуризацию можно применять и к объектам!
Более того, извлечение из объектных литералов допускает переименование извлекаемых свойств, а также задание значений по умолчанию!
const { a: myField = 'default_value' } = { a: 'Hello world!' }
извлекаем свойство a
в константу myField
со значением по умолчанию 'default_value'
№3 Оператор многоточие (spread–operator)
const [ first, ...rest ] = [ a, b, c ]
Извлечение отдельных значений из массивов и объектов это конечно хорошо, но когда нам нужно извлечь сразу много значений (или все) пригодится оператор многоточия.
В примере ниже мы извлекаем первый элемент массива в константу first, а все остальные укладываем в rest
const [ first, ...rest ] = [ 0, 1, 2, 3, 4 ]
console.log(first) // 0
console.log(rest) // [ 1, 2, 3, 4 ]
Вот так можно извлекать данные из объектов с помощью spread–оператора:
const employee = {
name: 'Петя',
age: 30,
salary: 30_000
}
const { salary, ...person } = employee
// salary -> 30_000
// person -> { name: 'Петя', age: 30 }
Но и это ещё не всё!
Оператор имеет широкое применение в функциях!
Помните выше я указывал что у анонимных функций внутри нет arguments? Этот оператор позволяет забыть об этой магической переменной:
// благодаря spread-оператору мы объединяем все аргументы в массиве args
const sum = (...args) =>
args.reduce((prev, current) => prev + current, 0)
// примеры вызова функции
sum(1, 2, 3, 4, 5) // -> 15
sum(1, 2) // -> 3
Вообще, этот оператор нашёл широкое применение. К примеру, теперь можно легко объединять массивы или объекты, а также распаковывать типы данных вроде Set:
const array1 = [ 0, 1, 2 ]
const array2 = [ 2, 3, 4 ]
// конкатенация массивов
const arrays = [ ...array1, ...array2 ] // [ 0, 1, 2, 2, 3, 4]
// лайфхак: убираем все дубли с помощью Set
const unique = [ ...(new Set(arrays)) ]
const obj1 = { a: 'a', b: 'b' }
const obj2 = { b: 'b2', c: 'c2' }
// объединение объектов
// свойства перезаписываются каждым последующим объектом!
const merged = { ...obj1, ...obj2 } // -> { a: 'a', b: 'b2', c: 'c2' }
Спасибо за внимание 😉
А какие конструкции JS больше всех нравятся тебе?
Пиши в коментах 👇, не стесняйся 👍