Всем привет!
Сегодня мы заберем важную тему → "Стрелочные функции JS"
Почему это важно?
Потому что мы уже почти отказались от Function Declaration
.
Пример:
// Стрелочная функция
const x = (a, b) => a + b
console.log(x(2, 3)) // 5
// Function declaration
function y(a, b) {
return a + b
}
console.log(y(2, 3))
Разберем содержание и начнем поэтапно =)
Содержание:
Стрелочные функции:
arguments
,hoisting
Работа с контекстом
Методы присваивания контекста
Обработчик событий
1. Стрелочные функции: arguments, hoisting
Итак, стрелочные функции появились с ES6 (если это интересно). Очень удобная вещь, особенно когда это касается упрощения кода!
Пример:
const sayHi = () => console.log("Привет")
Выглядит очень удобно, не занимает много строк, а ещё радует момент — это hoisting
.
Hoisting
— это всплытие.
Могут всплывать переменные и функции.
Пример переменной:
console.log(a) // undefined
var a = 5
Переменная уже вызвана, не выдает ошибку, но пока undefined
.
Пример function declaration (обычной функции):
sayHello() // Привет
function sayHello() {
console.log("Привет")
}
Мы вызываем функцию, которая ещё не задана, но она вызывается и выполняется.
Это и называется hoisting
.
Пример стрелочной функции:
sayHi() // ❌ Ошибка: TypeError: sayHi is not a function
const sayHi = () => console.log("Привет")
А в стрелочных функциях выдает ошибку: "Нет такой функции x, дружище"
И это здорово — не будет проблем с работой функций и подменой!
У обычной функции есть arguments,
а у стрелочных функций такого нет. Что это такое?
Пример:
function test() {
console.log(arguments)
}
test('Первая', 'статья') // { 0: "Первая", 1: "статья" }
А вот стрелочные функции используют ...rest:
const test = (...args) => console.log(args)
test('Первая', 'статья') // ['Первая', 'статья']
Обязательно! Обратите внимание, что обычные функции выдают объект, а стрелочные функции выдают массив — потому что это ...rest
.
Если хотите также объектом, вот простой пример:
const test = (...args) => Object.assign({}, args)
console.log(test('Первая', 'статья')) // {0: "Первая", 1: "статья"}
Это добавляет объект с методом, можно еще покороче:
const test = (...args) => ({...args})
console.log(test('Первая', 'статья')) // {0: "Первая", 1: "статья"}
Что такое ( {...} ) ?
Если нам нужно выдать объект, то добавляем ()
:
const getUser = () => ({ name: "Ник Уайт"})
const people = getUser()
console.log(people.name) // Ник Уайт
без скобок вернёт undefined
, потому что интерпретирует {}
как тело функции
Если мы хотим использовать внутри функции несколько переменных, или несколько функций, методов и т.д. — то мы делаем это не в одну строку:
const sum = (a, b) => {
const result = a + b
return result
}
console.log(sum(2, 3)) // 5
Итак, мы разобрали работу и отличие обычных функций от стрелочных! Но это еще не все, очень важные темы еще впереди, предлагаю продолжить!)
2. Работа с контекстом
Контекст — очень важная тема, особенно при присваивании и использовании! В случае его потери могут возникнуть серьёзные проблемы, которые сложно отследить в коде, особенно если он состоит не из пары строк.
Разберем пример с обычной функцией:
const nick = {
name: 'Ник Уайт',
getUser: function () {
return this.name
}
}
console.log(nick.getUser()) // Ник Уайт
Всё хорошо — контекст не теряется, и всё работает отлично, как и должно быть!
Мы создаём ключ name: 'Ник Уайт'
и обращаемся к нему через функцию getUser
, которая использует this.name
и возвращает нужный результат.
Пример стрелочной функции:
const nick = {
name: 'Ник Уайт',
getUser: () => {
return this.name
}
}
console.log(nick.getUser()) // undefined
Казалось бы, да — код почти тот же, изменились лишь мелочи. Но теперь контекст меняется. А почему так происходит?
Происходит так, потому что стрелочные функции не имеют собственного this
— они берут его из внешнего контекста.
А внешний контекст здесь — это window
(в браузере), а не obj
.
(если бы была обычная функция, то this
указывал бы на obj
, и всё работало бы как надо)
const nick = {
name: 'Ник Уайт',
getUser: function() {
const name = this.name
const arrow = () => name
return arrow()
}
}
console.log(nick.getUser()) // Ник Уайт
Это один из способов использовать стрелочную функцию внутри обычной функции, когда нужно сохранить контекст this
или просто передать нужные данные в стрелку. Это удобно, когда, например, нужно вызывать функцию внутри setTimeout
, map
, filter
и т.д., где легко потерять контекст.
Обязательно! Это частые вопросы на собеседованиях, изучив и попрактиюсь пару раз, запомните это!
3. Методы присваивания контекста
Контекст можно присваивать и получать нужный результат, при этом функция будет общей и сможет работать с любым контекстом!
Пример:
const obj = {
name: 'Ник Уайт',
getUser: function() {
return this.name
}
}
const people = obj
console.log(obj.getUser.apply({name: 'Alex'})) // Alex
Простой пример: у нас есть объект с ключами name
и getUser
. В getUser
хранится функция, у которой контекст — сам объект с name
. Мы создаем переменную people
, которая ссылается на объект obj
, и через метод присваиваем контекст — объект с name: 'Alex'
. И это будет работать!
У нас есть 3 метода присваивания контекста: bind, call, apply.
bind
— возвращает новую функцию с привязанным this
function sayHello() {
return `Привет, ${this.name}`
}
const user = { name: 'Ник' }
const sayHelloToNick = sayHello.bind(user)
console.log(sayHelloToNick()) // Привет, Ник
bind
не вызывает функцию сразу, а просто создаёт копию с нужным контекстом.
call
— вызывает функцию сразу, передавая this
и аргументы
function greet(message) {
console.log(`${message}, ${this.name}`)
}
const user = { name: 'Ник' }
greet.call(user, 'Добро пожаловать') // Добро пожаловать, Ник
call
полезен, когда нужно быстро вызвать функцию с другим контекстом.
apply
— почти как call
, но аргументы передаём массивом
function greet(message, emoji) {
console.log(`${message}, ${this.name} ${emoji}`)
}
const user = { name: 'Ник' }
greet.apply(user, ['Салют', '?']) // Салют, Ник ?
apply
удобен, если аргументы уже есть в массиве.
Самый большой минус — методы присваивания не работают со стрелочными функциями! Почему? Потому что у стрелочных функций нет собственного this, они просто берут его из внешнего контекста при создании.
Что мы можем сделать?
создать функцию, внтури сделать пременную ссылающиеся на контекст и сделать callback или просто вызывать стрелочную функцию ссылающиеся на созданную переменную!
4. Обработчик событий
Вот мы и подошли к важной теме — обработка событий, особенно при использовании стрелочных и обычных функций!
В чём разница?
Обычная функция:
const button = document.querySelector('button')
button.addEventListener('click', function () {
console.log(this) // this указывает на саму кнопку
})
Здесь this
ссылается на элемент, который вызвал событие (в данном случае — button
). Это удобно, если нам нужно что-то изменить прямо на этом элементе.
Стрелочная функция:
const button = document.querySelector('button')
button.addEventListener('click', () => {
console.log(this) // this будет window (или undefined в strict)
})
В стрелочной функции this
не переопределяется и берётся из внешнего контекста. Поэтому внутри обработчика this
уже не будет ссылаться на кнопку.
Запомни: стрелочную функцию лучше не использовать в обработчиках событий, если тебе нужен
this
.
Итог:
Мы разобрали работу стрелочных функций, их отличие от обычных функций!
Они очень удобные в сокращении кода, а также имеют свои особенности и различия.
Стрелочные функции мы используем практически везде, особенно в React, где они помогают писать лаконичный и читаемый код!
Мой канал в Telegram: https://t.me/nickwhite_web
Там я выкладываю посты и новости по JavaScript и Web-разработке.
Хаб по JavaScript: https://github.com/n1ckwhite/JavaScript-Universe
Здесь вы найдёте:
Часто задаваемые вопросы на собеседованиях
Полезные задачи
Обучающие статьи по написанию скриптов
Буду всегда рад помочь и поделиться новостями! Спасибо за чтение ?
Комментарии (8)
CzarOfScripts
12.06.2025 10:11Не понимаю любовь людей к стрелочным функциям, в большинстве случаев они излишни и некрасивы. Особенно когда нужно еще и типизацию накидывать.
n1ckwhite Автор
12.06.2025 10:11Важно еще и работа с контекстом! В некоторых случаях контекст не добыть)
winkyBrain
12.06.2025 10:11в большинстве случаев они излишни
ну разве что в случае, если вы совсем динозавр и использование function уже выбито у вас на подкорке) иначе крайне сомнительно называть то, где наоборот нет ничего лишнего(нет возни с контекстом, нет всплытия - всё это как раз и не нужно в большинстве случаев) излишним. это такая старательная подмена понятий что ли?)
winkyBrain
12.06.2025 10:11материал можно ужать до нескольких предложений: если нужен контекст или всплытие - юзаем function, в остальных случаях достаточно стрелочных функций. всё это пережёвано на просторах интернета уже сотни раз
p_k
12.06.2025 10:11Вообще можно задать вопрос AI и он тебе всё расскажет, но есть человеческий фактор который может по разному трактовать
Vitaly_js
12.06.2025 10:11Самый большой минус — методы присваивания не работают со стрелочными функциями! Почему? Потому что у стрелочных функций нет собственного this, они просто берут его из внешнего контекста при создании.
По моему, зря вы так выразились, потому что стрелочные функции так же наследуют все свойства прототипа Function. Поэтому разумеется у них есть и call, bind, apply. И работают точно так же, но контекст не задают, потому что у стрелочных функций его нет.
pnmv
Здесь, нужен тег "ненормальное программирование".
Чего ещё нехватает: рассказа о том, что с производительностью у данной обёртки.
Тезис об улучшении читабельности - весьма спорный.
n1ckwhite Автор
Спасибо, учту момент:)