Jeden przykład dotyczy zamknięcia, drugi nie. Wdrożenie zamknięć jest dość trudne, ponieważ zmienne zamknięte nad zmiennymi nie działają jak zmienne normalne. Jest to bardziej oczywiste w języku niskiego poziomu, takim jak C, ale zilustruję to JavaScript.
Zamknięcie składa się nie tylko z funkcji, ale także ze wszystkich zmiennych, które zamknął. Kiedy chcemy wywołać tę funkcję, musimy również podać wszystkie zmienne zamknięte. Możemy modelować zamknięcie za pomocą funkcji, która otrzymuje obiekt jako pierwszy argument reprezentujący te zamknięte zmienne:
function add(vars, y) {
vars.x += y;
}
function getSum(vars) {
return vars.x;
}
function makeAdder(x) {
return { x: x, add: add, getSum: getSum };
}
var adder = makeAdder(40);
adder.add(adder, 2);
console.log(adder.getSum(adder)); //=> 42
Zwróć uwagę na niezręczną konwencję wywoływania, która closure.apply(closure, ...realArgs)
tego wymaga
Obsługa wbudowanych skryptów JavaScript umożliwia pominięcie jawnego vars
argumentu i pozwala this
zamiast tego użyć :
function add(y) {
this.x += y;
}
function getSum() {
return this.x;
}
function makeAdder(x) {
return { x: x, add: add, getSum: getSum };
}
var adder = makeAdder(40);
adder.add(2);
console.log(adder.getSum()); //=> 42
Te przykłady są równoważne z tym kodem, który faktycznie używa zamknięć:
function makeAdder(x) {
return {
add: function (y) { x += y },
getSum: function () { return x },
};
}
var adder = makeAdder(40);
adder.add(2);
console.log(adder.getSum()); //=> 42
W tym ostatnim przykładzie obiekt służy tylko do grupowania dwóch zwróconych funkcji; this
wiązania nie ma znaczenia. Wszystkie szczegóły umożliwiające zamknięcie - przekazywanie ukrytych danych do faktycznej funkcji, zmiana wszystkich dostępów do zmiennych zamknięcia na wyszukiwanie w tych ukrytych danych - są obsługiwane przez język.
Ale wywoływanie zamknięć wiąże się z narzutem związanym z przekazywaniem tych dodatkowych danych, a uruchomienie zamknięcia wiąże się z narzutem związanym z wyszukiwaniem tych dodatkowych danych - pogarszanym przez złą lokalizację pamięci podręcznej i zwykle dereferencję wskaźnika w porównaniu ze zwykłymi zmiennymi - więc nie jest zaskakujące, że rozwiązanie, które nie opiera się na zamknięciach, działa lepiej. Zwłaszcza, że wszystko, co oszczędza ci zamknięcie, to kilka wyjątkowo tanich operacji arytmetycznych, które mogą być nawet stale składane podczas analizowania.