Замыкание в JavaScript — это функция, которая имеет доступ к переменным и параметрам своей внешней функции даже после возврата внешней функции. Это означает, что замыкание может запоминать и обращаться к переменным в той области видимости, в которой оно было создано, даже если создавшая его функция завершила выполнение и ее область видимости была уничтожена.
Закрытие создается, когда внутренняя функция ссылается на переменную из внешней функции. Внутренняя функция сохраняет ссылку на переменную внешней функции, и эта ссылка называется замыканием.
Зачем использовать замыкания?
Замыкания полезны, поскольку они позволяют разрабатывать приватные переменные и функции в JavaScript. Доступ к таким переменным и функциям возможен только в рамках функции, в которой они были определены.
Функция замыканий сделает ваш код очень понятным и модульным. Предположим, что необходимо сохранить счетчик внутри функции, гарантируя при этом, что переменная счетчика недоступна извне функции. В этом случае замыкание может быть использовано для создания конфиденциальной переменной счетчика.
Частные переменные в замыканиях
Допустим, у нас есть функция, которая должна отслеживать счетчик, однако мы не хотим, чтобы счетчик был доступен извне функции. Мы можем использовать замыкание для создания частной переменной-счетчика, например:
function counter() { let myCounter = 0 return function() { myCounter++; console.info(myCounter, 'myCounter') } } const increaseCounter = counter() increaseCounter() // 1 increaseCounter() // 2 increaseCounter() // 3
Давайте немного взглянем на код: функция handleClick создает вложенную функцию, которая может получить доступ к переменной count. Чтобы использовать эту функцию в качестве обратного вызова для метода addEventListener, мы присваиваем ее переменной incrementClickCount. При каждом нажатии кнопки вызывается функция incrementClickCount, и значение переменной count увеличивается. Поскольку переменная count определена внутри функции handleClick, доступ к ней вне функции невозможен, что делает ее закрытой переменной.
Слушатели событий в замыканиях
Замыкания также чаще всего используются с прослушивателями событий. Допустим, у нас есть кнопка, к которой мы хотим добавить прослушиватель событий щелчка, однако мы хотим отслеживать, сколько раз кнопка была нажата. Мы можем использовать замыкание, чтобы создать приватную переменную cliced
и прикрепить прослушиватель событий к кнопке следующим образом:
<button id="myButton">Click me</button> <script> const myButton = document.getElementById('myButton'); function handleClick() { let clicked = 0; return function() { clicked++; console.info(`Button clicked ${clicked} times`); } } const increaseClickCount = handleClick(); myButton.addEventListener('click', increaseClickCount); </script>
В этом примере функция handleClick
возвращает внутреннюю функцию, которая имеет доступ к переменной clicked
. Мы устанавливаем переменную increaseClickCount
в возвращаемую внутреннюю функцию, чтобы мы могли передать ее в качестве функции обратного вызова методу addEventListener
.
Всякий раз, когда мы нажимаем кнопку, increaseClickCount
функция будет выполняться, тогда наша переменная clicked будет увеличена. Поскольку переменная clicked
объявлена внутри функции handleClick
, она недоступна извне функции, что делает ее частной переменной.
Реализация частного модуля
Замыкания также можно использовать для создания частных модулей в JavaScript. Приватный модуль — это модуль, который имеет приватные переменные и функции, недоступные снаружи модуля.
const calculator = (function() { let result = 0; function add(x) { result += x; } function subtract(x) { result -= x; } function multiply(x) { result *= x; } function divide(x) { result /= x; } function getResult() { return result; } return { add: add, subtract: subtract, multiply: multiply, divide: divide, getResult: getResult } })(); calculator.add(5); calculator.multiply(2); console.info(calculator.getResult()); // prints 10
В этом блоке кода переменная calculator
назначается немедленно вызываемому функциональному выражению (IIFE), которое возвращает объект, содержащий функции, которые можно использовать для выполнения арифметических операций. Переменная result
объявлена внутри закрытия IIFE и недоступна снаружи модуля calculator
. Это позволяет нам создать приватный модуль с приватными переменными и функциями, доступ к которым можно получить только через функции, которые возвращаются из модуля.
Эти примеры демонстрируют гибкость и полезность замыканий в разработке JavaScript. Используя возможности замыканий, мы можем создавать более модульный, удобный и эффективный код.
Реализация функций обратного вызова
Замыкания также часто используются в JavaScript для реализации функций обратного вызова. Функция обратного вызова — это функция, которая передается в качестве аргумента другой функции и выполняется, когда происходит определенное событие или когда выполняется определенное условие.
function waitThenDo(callback, time) { setTimeout(function() { callback(); }, time); } function sayHello() { console.info('Hello!'); } waitThenDo(sayHello, 1000); // waits 1 second before logs 'Hello!'
В этом примере функция waitThenDo()
принимает два аргумента.
1-) функция обратного вызова
2-) время в миллисекундах.
Он использует метод setTimeout()
для задержки выполнения функции обратного вызова на указанное время. По истечении времени запускается функция обратного вызова. В этом случае функция sayHello()
выполняется как функция обратного вызова и запускается с задержкой в 1 секунду.
Создание мемоизированной функции в замыканиях
Запоминаемая функция — это функция, которая кэширует результаты предыдущих вызовов функций и возвращает кэшированный результат при повторном использовании того же ввода. Этот метод можно использовать для оптимизации функций, которые требуют больших вычислительных ресурсов или имеют повторяющиеся вычисления. И на мой взгляд, это самая функциональная вещь для замыканий в Javascript-разработках. Кроме того, я считаю, что этот подзаголовок — запомненные функции — необходимо объяснить в отдельном сообщении в блоге, и это действительно улучшает производительность. Всякий раз, когда мы можем использовать это, мы должны использовать это, это не должно быть дополнительным способом.
function memoize(func) { const cache = {}; return function(...args) { const key = JSON.stringify(args) if (cache[key]) { console.info('Returning from cache...') return cache[key] } console.info('Calculating result...') const result = func.apply(this, args) cache[key] = result return result } } function expensiveFunction(x, y) { console.info('Calculating...') return x * y } const memoizedFunction = memoize(expensiveFunction) console.log(memoizedFunction(5, 10)) // Calculating result...50 console.log(memoizedFunction(5, 10)) // Returning from cache...50 console.log(memoizedFunction(10, 20)) // Calculating result...200 console.log(memoizedFunction(10, 20)) // Returning from cache...200
Здесь функция memoize()
принимает функцию в качестве входных данных и возвращает новую функцию, которая кэширует результаты предыдущих вызовов функций. Кэшированные результаты сохраняются в объекте cache
, который объявляется в закрытии возвращаемой функции. Когда возвращаемая функция вызывается с теми же входными данными, она возвращает кэшированный результат, а не пересчитывает его. Поэтому мы не будем тратить свои ресурсы, так как возвращаем результат из кеша, а не вычисляем заново.
Раскройте потенциал JavaScript с помощью этого подробного руководства по замыканиям для начинающих.
С помощью замыканий в JavaScript вы сможете вывести свои навыки кодирования на новый уровень и писать более безопасный, эффективный и модульный код.
Осваивая концепции и примеры замыканий в JavaScript, новички могут вывести свои навыки программирования на новый уровень и создавать более эффективные и мощные приложения JavaScript.