Funkcja - obiekt pierwszej klasy
JavaScript jest językiem obiektowo-funkcyjnym. Jego twórca, Brendan Eich, miał za zadanie stworzyć język, który będzie Scheme
w przedlądarce oraz będzie wyglądał jak Java
.
W JavaScript wszystko jest obiektem, również funkcja. A dokładniej funkcje są obiektami pierwszej klasy. Oznacza to, że możemy z nimi zrobić dokładnie to samo co z innymi obiektami. Ważną cechą funkcji jest to, że mogą zostać wywołane przy użyciu ()
.
Możemy przypisać funkcję do zmiennej.
Przykład 1.1
let greet = function (name) {
return `Hello, my name is ${name}.`;
}
Możemy przekazać funkcję jako parametr do innej funkcji.
Przykład 1.2
const name = 'John Doe';
function greeter (greet) {
console.log(greet(name));
}
Możemy również zwrócić funkcję jako wynik innej funkcji.
Przykład 1.3
function createGreeter () {
return function (name) {
return `Hello, my name is ${name}.`;
}
}
Własność length
obiektu funkcji pozwala sprawdzić ilość jej formalnych argumentów.
Przykład 1.4
function greet (name, age, city) {
return `My name is ${name}, I am ${age} years old and from ${city}.`;
}
console.log( greet.length ); // -> 3
Funkcje wyższego poziomu
Funkcje wyższego pozioku (z ang. high order functions) są funkcjami, które przyjmują inne funkcje jako argumenty.
Przykład 1.5
function applyAction (numbers, action) {
for (let number of numbers) {
action(number);
}
}
applyAction([1, 2, 3, 4], console.log);
Dzięki wykorzystaniu podejścia funkcyjnego możemy sprawić, że nasz kod stanie się bardziej czytelny, łatwiejszy w utrzymaniu i ponownym wykorzystaniu.
Załóżmy, że mamy tablicę liczb od 1 do 10. Chcemy wypisać liczby parzyste. Zacznijmy od wersji imperatywnej.
Przykład 1.6
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
for (let num of numbers) {
if (num % 2 === 0) {
console.log(num);
}
}
// -> 2
// -> 4
// -> 6
// -> 8
// -> 10
Zobaczmy jak wygląda wersja funkcyjna tego kodu.
Przykład 1.7
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
function printNumbers (numbers, printer, condition) {
numbers.forEach(num => {
if (condition(num)) {
printer(num);
}
});
}
const isEven = num => num % 2 === 0;
printNumbers(numbers, console.log, isEven);
Ta wersja zapewnia nam dużą elastyczność. Możemy dowolnie sterować działaniem funkcji printNumbers()
podczas jej wywoływania. Dodatkowo wersja funkcyjna spełnia zasadę RSP - (ang. single responsibility principle). Funkcja isEven() ma jedno i tylko jedno zadanie - sprawdzić czy liczba jest parzysta. Podobnie funckja printNumbers() zajmuje się wypisaniem liczb. Nie skupia się nad tym w jaki sposób je wypisać ani na tym, które z nich.
Czego brakuje w JavaScript?
Jednak JavaScript nie jest w pełni językiem funkcyjnym. Brakuje mu kliku ważnych elementów.
czystych funkcji - pure functions - czyli funkcji bez efektów ubocznych, np.
console.log()
,niezmiennego stanu - możemy wykorzystać
const
czy teżObject.freez()
,tail call optimization - JavaScript wspiera rekursję ale nie obsługuje poprawnie optymalizacji rekursji.
O czym będziemy mówić
Będziemy mówili o tym jak wykorzystać elementy programowania funkcyjnego aby nasz kod w JavaScript stał się bardziej czytelny oraz reużywalny.
Przyjrzymy się:
- przetwarzaniu potokowym na przykładzie kolekcji,
- programowaniu reaktywnym na przykładzie
RxJS
iObservables
.