Как стать автором
Обновить

Стрелочные функции JS, быстро, просто и без проблем

Уровень сложностиСредний

Всем привет!

Сегодня мы заберем важную тему → "Стрелочные функции 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))

Разберем содержание и начнем поэтапно =)

Содержание:

  1. Стрелочные функции: arguments, hoisting

  2. Работа с контекстом

  3. Методы присваивания контекста

  4. Обработчик событий


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 obj = {
  name: 'Ник Уайт',
  getUser: function () {
    return this.name
  }
}

const nick = obj

console.log(nick.getUser()) // Ник Уайт

Всё хорошо — контекст не теряется, и всё работает отлично, как и должно быть!

Мы создаём ключ name: 'Ник Уайт' и обращаемся к нему через функцию getUser, которая использует this.name и возвращает нужный результат.

Пример стрелочной функции:

const obj = {
  name: 'Ник Уайт',
  getUser: () => {
    return this.name
  }
}

const nick = obj

console.log(nick.getUser()) // undefined

Казалось бы, да — код почти тот же, изменились лишь мелочи. Но теперь контекст меняется. А почему так происходит?

Происходит так, потому что стрелочные функции не имеют собственного this — они берут его из внешнего контекста.
А внешний контекст здесь — это window (в браузере), а не obj.

(если бы была обычная функция, то this указывал бы на obj, и всё работало бы как надо)

const obj = {
  name: 'Ник Уайт',
  getUser: function() {
    const name = this.name
    const arrow = () => name
    return arrow()
  } 
}

const nick = obj

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

Здесь вы найдёте:

  • Часто задаваемые вопросы на собеседованиях

  • Полезные задачи

  • Обучающие статьи по написанию скриптов

Буду всегда рад помочь и поделиться новостями! Спасибо за чтение 🙂

Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.