6.1 Pojęcie domknięć
Domknięcia są jedną z najważniejszych i najbardziej potężnych koncepcji w JavaScript. Pozwalają funkcjom zapamiętać swoje leksykalne otoczenie nawet po ich wykonaniu. W tym wykładzie omówimy pojęcie domknięć, ich cechy oraz podamy różne przykłady ich użycia.
Domknięcie (closure) w JavaScript to połączenie funkcji i leksykalnego otoczenia, w którym funkcja została zadeklarowana. Domknięcie pozwala funkcji "zapamiętać" i uzyskać dostęp do zmiennych i innych funkcji z jej zewnętrznego obszaru widoczności nawet po tym, jak zewnętrzna funkcja została wykonana.
Podstawowe właściwości domknięć:
- Leksykalne otoczenie: kontekst, w którym funkcja została zadeklarowana, w tym wszystkie zmienne dostępne w momencie deklaracji.
- Zachowanie kontekstu: funkcja z domknięciem może zachować dostęp do zmiennych z zewnętrznego obszaru widoczności nawet po zakończeniu działania tej zewnętrznej funkcji.
6.2 Przykłady działania domknięć
Przykład 1: Proste domknięcie
W tym przykładzie innerFunction()
ma dostęp do zmiennej outerVariable
z jej zewnętrznego
obszaru widoczności nawet po zakończeniu działania outerFunction()
.
function outerFunction() {
let outerVariable = 'I am from the outer function';
function innerFunction() {
console.log(outerVariable);
}
return innerFunction;
}
const closure = outerFunction();
closure(); // Wyświetli: I am from the outer function
Przykład 2: Licznik z użyciem domknięcia
W tym przykładzie funkcja-licznik przechowuje wartość zmiennej count
i zwiększa ją przy każdym wywołaniu.
function createCounter() {
let count = 0;
return function() {
count++;
return count;
};
}
const counter = createCounter();
console.log(counter()); // Wyświetli: 1
console.log(counter()); // Wyświetli: 2
console.log(counter()); // Wyświetli: 3
Przykład 3: Domknięcie w pętli
Domknięcia są często używane do przechowywania wartości zmiennych w pętlach.
W tym przykładzie każda funkcja w tablicy arr
"zapamiętuje" wartość zmiennej i
w momencie swojego stworzenia dzięki blokowemu obszarowi widoczności let
:
function createArrayWithClosures() {
let arr = [];
for (let i = 0; i < 3; i++) {
arr[i] = function() {
console.log(i);
};
}
return arr;
}
const closures = createArrayWithClosures();
closures[0](); // Wyświetli: 0
closures[1](); // Wyświetli: 1
closures[2](); // Wyświetli: 2
6.3 Złożone scenariusze użycia domknięć
Przykład 1: Częściowe stosowanie funkcji (partial application)
Domknięcia umożliwiają tworzenie częściowo zastosowanych funkcji, zachowując pewne argumenty jako stałe.
W tym przykładzie funkcja multiply()
zwraca funkcję, która mnoży przekazany jej argument b
przez stały argument a
.
function multiply(a) {
return function(b) {
return a * b;
};
}
const double = multiply(2);
console.log(double(5)); // Wyświetli: 10
console.log(double(10)); // Wyświetli: 20
Przykład 2: Ukrywanie danych (data hiding)
Domknięcia mogą być używane do tworzenia prywatnych zmiennych i metod.
W tym przykładzie zmienne _name
i _age
są prywatne i dostępne tylko przez metody obiektu:
function createPerson(name, age) {
let _name = name;
let _age = age;
return {
getName: function() {
return _name;
},
getAge: function() {
return _age;
},
setName: function(newName) {
_name = newName;
},
setAge: function(newAge) {
_age = newAge;
}
};
}
const person = createPerson('John', 30);
console.log(person.getName()); // Wyświetli: John
person.setName('Jane');
console.log(person.getName()); // Wyświetli: Jane
console.log(person.getAge()); // Wyświetli: 30
Przykład 3: Memoizacja
Memoizacja to technika optymalizacji, w której wyniki funkcji są przechowywane, aby uniknąć powtórnych obliczeń dla tych samych danych wejściowych.
W tym przykładzie funkcja memoize()
używa domknięcia do przechowywania cache obliczonych wyników funkcji fn()
:
function memoize(fn) {
const cache = {};
return function(...args) {
const key = JSON.stringify(args);
if (cache[key]) {
return cache[key];
}
const result = fn(...args);
cache[key] = result;
return result;
};
}
function slowFunction(num) {
console.log('Computing...');
return num * 2;
}
const memoizedFunction = memoize(slowFunction);
console.log(memoizedFunction(5)); // Wyświetli: Computing... 10
console.log(memoizedFunction(5)); // Wyświetli: 10 (rezultat z cache)
GO TO FULL VERSION