В JavaScript замыкание (closure) — это функция, которая запоминает свои внешние переменные и имеет доступ к ним даже после того, как эта функция была выполнена.
Когда функция объявляется, у нее создается лексическое окружение (lexical environment), которое включает в себя все объявленные переменные и функции внутри этой функции. При этом каждый раз при создании нового экземпляра функции запоминается ссылка на то лексическое окружение, в котором она была создана. Именно это сохранение ссылки на лексическое окружение позволяет функции сохранять доступ к внешним переменным даже после того, как она была выполнена и вышла из стека вызовов.
Классическим примером использования замыкания является работа с приватными переменными в JavaScript. Ведь в самом языке не предусмотрен специальный модификатор доступа для переменных, но с помощью замыкания можно создать эффект приватности.
Определение замыкания
Замыкание (closure) в программировании — это функция вместе со всеми доступными ей переменными из объемлющей ее области видимости. Здесь функция является «замкнутой» вокруг этих переменных, что позволяет ей использовать их в любой момент времени, даже после завершения работы объемлющей функции.
В отличие от обычной функции, которая имеет доступ только к переменным, переданным ей в качестве аргументов или определенным внутри самой функции переменным, замыкания могут сохранять доступ к переменным внутри своей лексической области видимости (scope). Это достигается путем сохранения ссылки на внешний контекст, в котором они были созданы.
Замыкания полезны в ситуациях, когда необходимо сохранить состояние переменных между вызовами функции или обеспечить доступ к определенным данным только через заданное API. Они часто используются в функциональном программировании и для создания приватных переменных и методов в объектно-ориентированном программировании.
Примеры использования замыкания
Замыкания в JavaScript имеют множество практических применений.
Ниже приведены несколько примеров, демонстрирующих использование замыканий:
Счетчик:
Замыкание можно использовать для создания счетчика, который может инкрементировать или декрементировать значение. Внутренняя функция, которая имеет доступ к внешней переменной, сохраняет текущее значение счетчика и при необходимости изменяет его.
Пример кода: Результат: function createCounter() {
let count = 0;
return function() {
return count++;
}
}const counter = createCounter();
console.log(counter()); // 0
console.log(counter()); // 1
console.log(counter()); // 20
1
2Кэширование:
Замыкания также могут использоваться для создания кэша данных. Внутренняя функция может сохранять значения аргументов и результатов для определенных входных данных, чтобы избежать повторных вычислений и улучшить производительность.
Пример кода: Результат: function createCache() {
const cache = {};
return function(key) {
if (key in cache) {
return cache[key];
}
const result = expensiveOperation(key);
cache[key] = result;
return result;
}
}function expensiveOperation(key) {
// expensive computation
return 'Result for ' + key;
}const getData = createCache();
console.log(getData('key1')); // Result for key1
console.log(getData('key2')); // Result for key2
console.log(getData('key1')); // Result for key1 (from cache)Result for key1
Result for key2
Result for key1 (from cache)Приватные переменные и методы:
Замыкания позволяют имитировать приватные переменные и методы в объектно-ориентированном коде. Путем объявления переменных во внутренней функции, они становятся скрытыми и недоступными извне.
Пример кода: Результат: function createCounter() {
let count = 0;
function increment() {
count++;
}
function decrement() {
count--;
}
return {
increment,
decrement
}
}const counter = createCounter();
counter.increment();
counter.increment();
counter.decrement();console.log(counter.count); // undefined
undefined
Обработчики событий:
Замыкания могут использоваться для передачи значений или сохранения контекста при добавлении обработчиков событий. Таким образом, внутренняя функция будет иметь доступ к внешним переменным и параметрам, чтобы выполнить определенные действия при срабатывании события.
Пример кода: Результат: function createButton(name) {
const button = document.createElement('button');
button.textContent = name;
button.addEventListener('click', function() {
console.log('Clicked ' + name);
});
return button;
}const button1 = createButton('Button 1');
const button2 = createButton('Button 2');document.body.appendChild(button1);
document.body.appendChild(button2);(Кликнуть на Button 1)
Clicked Button 1
(Кликнуть на Button 2)
Clicked Button 2
Вопрос-ответ
Что такое замыкание функции?
Замыкание функции — это функция, которая запоминает своё окружение, включая переменные, объявленные во внешней области видимости, даже после того, как выполнение внешней функции завершается. Таким образом, замыкание может обращаться к переменным, которые находятся вне его области видимости.
Как объявить замыкание функции?
Замыкание функции можно объявить двумя способами: с использованием функции-литерала или с использованием функции-конструктора. Часто для объявления замыканий функции-литералы используются чаще, так как они более компактные и удобные в использовании.
Можно ли передавать замыкания функциям в качестве аргументов?
Да, замыкания можно передавать в качестве аргументов другим функциям. Это очень полезная возможность, которая позволяет создавать более гибкий и модульный код. Например, замыкания можно использовать для создания обработчиков событий, которые могут быть переданы в функцию, обрабатывающую события.