Closures in Javascript
Closures are a fundamental concept in JavaScript, allowing functions to "remember" the environment in which they were created, even after that environment has finished executing. Here are a couple of examples that demonstrate closures in action.
Example 1: Basic Closure
In this example, an inner function retains access to the variables of its outer function, even after the outer function has completed.
function makeCounter() {
let count = 0;
return function() {
count += 1;
return count;
};
}
const counter = makeCounter();
console.log(counter()); // Output: 1
console.log(counter()); // Output: 2
console.log(counter()); // Output: 3
Explanation
makeCounter
defines a variablecount
and returns a function that incrementscount
by 1 each time it is called.When
makeCounter
is called, it returns the inner function, which "closes over" thecount
variable. Even aftermakeCounter
has finished executing, the returned function retains access tocount
because of the closure.
Example 2: Closure with Parameters
Closures can also capture arguments passed to the outer function, creating a more flexible way to maintain state.
function createMultiplier(multiplier) {
return function(number) {
return number * multiplier;
};
}
const double = createMultiplier(2);
const triple = createMultiplier(3);
console.log(double(5)); // Output: 10
console.log(triple(5)); // Output: 15
Explanation
createMultiplier
takes amultiplier
as an argument and returns a function that multiplies any given number by thatmultiplier
.double
andtriple
retain the multiplier values2
and3
, respectively, because of the closure.When calling
double(5)
andtriple(5)
, the returned functions remember the values passed tocreateMultiplier
, allowingmultiplier
to persist.
Example 3: Private Variables Using Closures
Closures can be used to create "private" variables in JavaScript, encapsulating data within a function scope.
function BankAccount(initialBalance) {
let balance = initialBalance;
return {
deposit(amount) {
balance += amount;
console.log(`Deposited: $${amount}. New Balance: $${balance}`);
},
withdraw(amount) {
if (amount <= balance) {
balance -= amount;
console.log(`Withdrew: $${amount}. New Balance: $${balance}`);
} else {
console.log("Insufficient funds.");
}
},
getBalance() {
return balance;
}
};
}
const account = BankAccount(100);
account.deposit(50); // Deposited: $50. New Balance: $150
account.withdraw(30); // Withdrew: $30. New Balance: $120
console.log(account.getBalance()); // Output: 120
Explanation
BankAccount
defines a private variablebalance
that is accessible only within thedeposit
,withdraw
, andgetBalance
functions.Even though
BankAccount
has finished executing, the returned object retains access tobalance
due to closures.This approach simulates private variables, as
balance
cannot be accessed directly outside of theBankAccount
function.
Subscribe to my newsletter
Read articles from David Gostin directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
David Gostin
David Gostin
Full-Stack Web Developer with over 25 years of professional experience. I have experience in database development using Oracle, MySQL, and PostgreSQL. I have extensive experience with API and SQL development using PHP and associated frameworks. I am skilled with git/github and CI/CD. I have a good understanding of performance optimization from the server and OS level up to the application and database level. I am skilled with Linux setup, configuration, networking and command line scripting. My frontend experience includes: HTML, CSS, Sass, JavaScript, jQuery, React, Bootstrap and Tailwind CSS. I also have experience with Amazon EC2, RDS and S3.