Funkcje z użyciem "strzałek" - czyli tak zwane arrow functions - to jedna z najciekawszych nowości w ES6. Rozwiązanie to pomaga nam w dwóch kwestiach za jednym zamachem:
- skraca kod i upraszcza deklarowanie funkcji anonimowych
- niweluje konieczność zapisywania this w dodatkowej zmiennej
Obie te kwestie omówimy na przykładach.
Uproszczenie składni
Zacznijmy od przykładu:
var array = [1, 2, 3, 4];
var result = array.map(function (x) {
return x * 2;
});
console.log(result); //[ 2, 4, 6, 8 ]
Kod ten zapisuje do zmiennej result
podwojone wartości z tablicy array
wykorzystując do tego metodę tablicową map()
(więcej na temat tej metody możesz przeczytać tutaj: JavaScript: Metody map(), filter() i IndexOf() - usprawnij swoją pracę z tablicami).
Teraz przepiszmy ten kod w ES6 z wykorzystaniem strzałek:
var array = [1,2,3,4];
var result = array.map(x => x * 2);
console.log(result); // [ 2, 4, 6, 8 ]
Kod jest dużo krótszy i czytelnieszy. Świetnie! A jak to dokładnie działa? Jak widzicie, znak strzałki =>
robi tutaj dwie rzeczy:
- zastępuje deklarację funkcji anonimowej
- niweluje konieczność użycia
return
w wyrażeniu
Najprościej rzecz ujmując, taki zapis w ECMAScript 6:
(x, y) => x + y
jest równoznaczny temu w ES5:
(function (x, y) {
return x * y;
});
Nawias przed strzałką można całkowicie pominąć, gdy przekazujemy tylko jeden argument, czyli np.:
x => x *2
jest równoznaczne następujacemu zapisowi w ES5:
(function (x) {
return x * 2;
});
Zalet tego rozwiązania nie trzeba nawet tłumaczyć, bo są widoczne na pierwszy rzut oka. Przejdźmy więc do drugiego, nieco ciekawszego akpektu używania arrow functions.
Brak konieczności zapisywania this do zmiennej
Zacznijmy może od tego, po co zapisywać this
do zmiennej w ES5. Przeanalizujmy poniższy kod:
function Tree() {
this.age = 0;
setInterval(function getOlder() {
this.age += 1;
console.log('Drzewo zostało zasadzone: ' + this.age + ' sekund temu');
}, 1000);
}
var tree = new Tree(); //zasadzenie drzewa
Kod ten w założeniu miał za zadanie zasadzić drzewo (utworzyć obiekt tree
z funkcji-konstruktora) i wyświetlać co sekundę ile czasu temu zostało zasadzone. I zdając się na intuicję można by przypuszczać, że to właśnie robi. Problem jednak w tym, że ten kod... nie zadziała.
A nie zadziała dlatego, że funkcja getOlder
tworzy swój własny zakres zmiennych, z własną instancją this
i w ten sposób this
do ktorego odnosimy się w linijce nr 5 to zupełnie inne this
niż to z linijki nr 2.
Dotychczas z problemem tym radziliśmy sobie zapisując zmienną this
w osobnej zmiennej, tak aby mieć do niej dostęp wewnątrz funkcji. Wyglądało to mniej więcej tak:
function Tree() {
var self = this;
self.age = 0;
setInterval(function getOlder() {
self.age += 1;
console.log('Drzewo zostało zasadzone: ' + self.age + ' sekund temu');
}, 1000);
}
var tree = new Tree();
Na szczęście czasy takiego kombinowania odchodzą w niepamięć wraz z nadejściem ES6. Arrow functions mają tę zaletę, że nie tworzą osobnej instancji this
, więc o problemie możemy zupełnie zapomnieć, a tę samą funkcjonalność osiągniemy poniższym kodem:
function Tree() {
this.age = 0;
setInterval(() => {
this.age += 1;
console.log('Drzewo zostało zasadzone: ' + this.age + ' sekund temu');
}, 1000);
}
var tree = new Tree();
Jak widać, jedyne, co zostało zmienione w stosunku do pierwotnego kodu, to zamiana funkcji getOlder()
na arrow function (przepraszam, ale funkcja strzałkowa brzmi po prostu źle :P) w czwartej linijce. To wszystko. Żadnego kombinowania, zastanawiania się, tworzenia śmiesznie nazywających się zmiennych. Dla mnie bomba.
Jedna rzecz, na którą być może zwróciliście uwagę, to fakt, że, jeśli chcemy pisać kod w ES6, to zamiast funkcji konstruktora Tree()
powinniśmy skorzystać tutaj z klas. I macie rację. Klasy to kolejna z wielkich nowości wprowadzonych w ECMAScript 6, które znacznie zwiększają czytelność kodu i ułatwiają jego pisanie. Ale tym tematem zająłem się w kolejnym artykule z serii o nowościach ES6, do którego lektury zapraszam: ECMAScript 6 - klasy.