Arrow functions - anonimowe funkcje poprawiające czytelność kodu

Arrow functions (funkcje strzałkowe) - to inna forma zapisu funkcji w JavaScripcie, która pojawiła się w ES6. Charakteryzuje je użycie strzałki =>, aby otrzymać krótszą formę zapisu. Sprawdza się to szczególnie dobrze, gdy tworzymy małe funkcje będące argumentami dla innych funkcji. W większości przypadków będziemy mogli zastąpić zwykle funkcje funkcjami strzałkowymi, jednak należy pamiętać o kilku ważnych różnicach - więcej o tym w dalszej części artykułu.

Arrow functions są funkcjami anonimowymi co oznacza, że nie posiadają nazwy, można je jednak przypisać do zmiennej i w ten sposób odwoływać się do funkcji.

Zobaczmy najprostszy sposób zamiany zwykłej funkcji na strzałkową:

function add(x, y) {
	return x + y;
}

// przypisujemy funkcję do zmiennej
const add = function(x, y) {
	return x + y;
}

// usuwamy "function" i dodajemy strzałkę po argumentach
const add = (x, y) => {
	return x + y;
}

Powyższy kod pokazuje 3 sposoby na zadeklarowanie funkcji. W ostatnim wykorzystujemy strzałkę =>, aby skrócić zapis funkcji. Zauważ, że nie potrzebujemy już słowa function do deklaracji funkcji. Zastępujemy je strzałką => użytą zaraz po liście argumentów.

Funkcje strzałkowe pozwalają na jeszcze większy skrót w zapisie:

// zwraca x + y
const add = (x, y) => (
	x + y
)
// zapis w jednej linii
const add = (x, y) => x + y

// pozbycie się nawiasów w przypadku jednego argumentu
const add1 = x => x + 1

Jeżeli jedynym elementem ciała funkcji jest zwrócenie innej wartości to możemy pozbyć się klamer {} oraz słowa return. Kod zapisany zaraz po strzałce => lub w nawiasach () będzie jednocześnie wartością zwracaną przez funkcję.

Należy jednak pamiętać o przypadku, gdy chcemy zwrócić obiekt.

// niepoprawny zapis
const createUser = (id, name) => {
	id: id,
	name: name
}

Taki zapis funkcji nie będzie działał, ponieważ wartości pomiędzy klamrami {} są traktowane jako ciało funkcji. Aby funkcja strzałkowa zwróciła obiekt skorzystamy z nawiasów.

const createUser = (id, name) => ({
	id: id,
	name: name
})

Zobaczmy jak arrow functions zwiększają czytelność, gdy funkcja zwraca inną funkcję:

function createAddFunction(number) {
	return function(x) {
		return x + number
	}
}

createAddFunction to funkcja tworząca inną funkcję. Możemy jej użyć do stworzenia funkcji zwracającą wartość większą o 1. Taką operację tworzenia funkcji przez inną funkcję nazywamy curryingiem . Temat ten rozwinąłem w innym poście - Currying w JavaScripcie.

const add1 = createAddFunction(1)
add1(5) // 6

Definicja funkcji createAddFunction może zostać znacznie skrócona:

// wersja pierwotna
function createAddFunction(number) {
	return function(x) {
		return x + number
	}
}

// zamiana na funkcje strzałkowe
const createAddFunction = number => (
	x => (
		x + number
	)
)

// wersja w jednej linii
const createAddFunction = number => x => x + number

Różnice między zwykłymi funkcjami, a strzałkowymi

Najbardziej istotną różnicą, która wpłynie na działanie naszych aplikacji jest różna wartość this w zwykłych funkcjach oraz strzałkowych.

this w funkcjach strzałkowych

Arrow functions nie tworzą własnego this lecz odziedziczają jego wartość, zależnie od miejsca, w którym zostały zdefiniowane. Wyjaśnienie czym dokładnie jest this w JavaScripcie zasługiwałoby na oddzielny post, jednak pokażę kilka przykładów w jaki sposób wykorzystać tę właściwość funkcji strzałkowych.

Jednak zobaczmy najpierw jak w praktyce zauważyć tę różnicę.

const logThisOutside = () => {
	console.log(this)
}

function MyButton() {
	this.name = 'My Button'
	function logThis() {
		console.log(this)
	}
	const logThisArrow = () => {
		console.log(this)
	}

	logThis() // Window
	logThisArrow() // { name: 'My Button' }
	logThisOuside() // Window
}

new MyButton()

Jak widzimy, logThisArrow oraz logThisOuside odziedziczyły wartość this zależnie od miejsca, w którym zostały zadeklarowane. Dzieje się tak dlatego, że arrow functions same nie tworzą this i tak jak w przypadku innych zmiennych, będą szukały tej wartości wyżej.

function MyButton() {
  this.name = 'My Button'

  const that = this
  document.querySelector("button").addEventListener("click", function() {
    console.log('click', this); // Button DOM Element
    console.log('that', that) // { name: 'My Button' }
    this.name = 'Button Clicked' // won't work as expected
    that.name = 'Button Clicked' // name value changed
  });

  document.querySelector("button").addEventListener("click", () => {
    console.log("click arrow", this); // { name: 'My Button' }
    this.name = 'Button Clicked' // name value changed
  });
}

new MyButton()

Stworzyliśmy dwa event listenery, w jednym wykorzystaliśmy zwykłą funkcję, w drugim strzałkową. W przypadku wykonania zwykłej funkcji po kliknięciu przycisku wartości this zostanie przypisany element DOM, który został kliknięty. Jeśli chcielibyśmy zmienić wartość this.name najpierw stworzyć zmienną const that = this.name , a następnie zmodyfikować name poprzez that.name = 'Button Clicked'. Jest to często spotykany hack, który umożliwia modyfikację this w przypadku zwykłych funkcji.

Jak już wspominałem, funkcje strzałkowe nie tworzą własnego this, dlatego możemy od razu modyfikować jego wartość poprzez this.name = 'Button Clicked'.

Brak arguments

Kolejną właściwością arrow functions jest brak dostępu do wartości arguments w funkcji.

function add() {
	console.log(arguments)
}

add(1, 2, 3) // console: [1, 2, 3]

Zwykła funkcja posiada dostęp do wartości arguments, która przechowuje informacje o argumentach, z którymi wykonana została funkcja. Funkcje strzałkowe nie mają dostępu do tej wartości, jednak w ES6 pojawiły się rest parameters, które skutecznie wypełniają lukę po braku arguments.

const add = (...args) => {
	console.log(args)
}

add(1, 2, 3) // console: [1, 2, 3]

Podsumowanie

Funkcje strzałkowe zwane też arrow functions oferują skrócony zapis funkcji. Pozwalają na pozbycie się słów kluczowych takich jak function i return, aby w bardziej czytelny sposób zadeklarować funkcję. Należy jednak uważać, aby przez zbyt duże zagnieżdżenie funkcji strzałkowych nie utrudnić czytania kodu.

Arrow functions nie tworzą własnego this oraz arguments co jest główną różnicą w porównaniu do zwykłych funkcji.

Dołącz do Newslettera

A będziesz na bieżąco ze wszystkimi postami na moim blogu.