JavaScript Functions are Closures
Every function in JavaScript is a closure. A closure is a function that has access to its own scope, the outer function’s scope, and the global scope.
Closures have several important capabilities in JavaScript:
Closures can maintain state
A closure remembers the variables from the outer scopes even after those scopes have exited. This means that functions can remember and update the values of variables they have “closed over”. This is often used to create functions with private internal state:
1 2 3 4 5 6 7 8 9 10 11
function counter() { let count = 0; return function() { return ++count; }; } let increment = counter(); console.log(increment()); // Outputs: 1 console.log(increment()); // Outputs: 2
In this example, each time
increment()
is called, it has access to thecount
variable from thecounter
function, even thoughcounter
has already returned.Closures can create private variables
JavaScript doesn’t natively support private variables, but closures can be used to achieve this functionality, providing a way to encapsulate or hide implementation details:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
function createSecret(secret) { return { getSecret: function() { return secret; }, setSecret: function(newSecret) { secret = newSecret; } }; } let secretKeeper = createSecret('my secret'); console.log(secretKeeper.getSecret()); // Outputs: 'my secret' secretKeeper.setSecret('new secret'); console.log(secretKeeper.getSecret()); // Outputs: 'new secret'
In this example,
secret
is a “private” variable that can’t be accessed directly. We have to use thegetSecret
andsetSecret
methods to interact with it.Closures can implement data hiding and encapsulation
Closures enable a form of data hiding and encapsulation, which are important concepts in object-oriented programming. Encapsulation allows us to bundle data with the methods that operate on that data. Data hiding allows an object to manage its own data, controlling access to it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
function createPerson(name) { let _name = name; return { getName: function() { return _name; }, setName: function(name) { _name = name; } }; } let person = createPerson('Alice'); console.log(person.getName()); // Outputs: Alice person.setName('Bob'); console.log(person.getName()); // Outputs: Bob
Here
_name
is encapsulated and hidden inside thecreatePerson
function, and can only be accessed and modified through thegetName
andsetName
methods.Closures allow for function factories
Closures can be used to create function factories, which are functions that return other functions, with specific behaviors:
1 2 3 4 5 6 7 8 9 10 11
function multiplier(factor) { return function(number) { return number * factor; }; } let doubler = multiplier(2); let tripler = multiplier(3); console.log(doubler(5)); // Outputs: 10 console.log(tripler(5)); // Outputs: 15
In this example, the
multiplier
function creates new functions that multiply their input by a specific factor.
Closures are one of the key concepts in JavaScript and understanding them is essential for mastering the language and writing efficient, professional-quality code.