6.1 Понятие замыканий
Замыкания являются одной из наиболее мощных и важных концепций в JavaScript. Они позволяют функциям запоминать свое лексическое окружение даже после того, как они были выполнены. В этой лекции мы рассмотрим понятие замыканий, их особенности и приведем различные примеры их использования.
Замыкание (closure) в JavaScript — это комбинация функции и лексического окружения, в котором эта функция была объявлена. Замыкание позволяет функции "запомнить" и получить доступ к переменным и другим функциям из своей внешней области видимости даже после того, как внешняя функция была выполнена.
Основные свойства замыканий:
- Лексическое окружение: контекст, в котором была объявлена функция, включая все переменные, доступные на момент объявления.
- Сохранение контекста: функция с замыканием может сохранить доступ к переменным из внешней области видимости даже после завершения выполнения этой внешней функции.
6.2 Примеры работы замыканий
Пример 1: Простое замыкание
В этом примере innerFunction() имеет доступ к переменной outerVariable из своей внешней области видимости даже после завершения выполнения outerFunction().
function outerFunction() {
let outerVariable = 'I am from the outer function';
function innerFunction() {
console.log(outerVariable);
}
return innerFunction;
}
const closure = outerFunction();
closure(); // Выведет: I am from the outer function
Пример 2: Счетчик с использованием замыкания
В этом примере функция-счетчик сохраняет значение переменной count и увеличивает его при каждом вызове.
function createCounter() {
let count = 0;
return function() {
count++;
return count;
};
}
const counter = createCounter();
console.log(counter()); // Выведет: 1
console.log(counter()); // Выведет: 2
console.log(counter()); // Выведет: 3
Пример 3: Замыкание в цикле
Замыкания часто используются для сохранения значений переменных в циклах.
В этом примере каждая функция внутри массива arr "запоминает" значение переменной i в момент своего создания благодаря блочной области видимости 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](); // Выведет: 0
closures[1](); // Выведет: 1
closures[2](); // Выведет: 2
6.3 Сложные сценарии использования замыканий
Пример 1: Частичное применение функции (partial application)
Замыкания позволяют создавать частично примененные функции, сохраняя некоторые аргументы фиксированными.
В этом примере функция multiply() возвращает функцию, которая умножает переданный ей аргумент b на зафиксированный аргумент a.
function multiply(a) {
return function(b) {
return a * b;
};
}
const double = multiply(2);
console.log(double(5)); // Выведет: 10
console.log(double(10)); // Выведет: 20
Пример 2: Скрытие данных (data hiding)
Замыкания могут использоваться для создания приватных переменных и методов.
В этом примере переменные _name и _age являются приватными и доступны только через методы объекта:
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()); // Выведет: John
person.setName('Jane');
console.log(person.getName()); // Выведет: Jane
console.log(person.getAge()); // Выведет: 30
Пример 3: Мемоизация
Мемоизация — это техника оптимизации, при которой результаты функции сохраняются, чтобы избежать повторных вычислений для одинаковых входных данных.
В этом примере функция memoize() использует замыкание для сохранения кеша вычисленных результатов функции 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)); // Выведет: Computing... 10
console.log(memoizedFunction(5)); // Выведет: 10 (результат взят из кеша)
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ