Closures are one of the most important concepts in JavaScript. They can look confusing at first because they involve functions, lexical scope, and lexical environments together. But once we understand how these concepts are connected, closures become much easier to understand.
A closure is a function that remembers and can access variables from its surrounding lexical environment even after the outer function has finished executing.
The word "remembers" here doesn't mean that JavaScript literally copies the variables into the function. Instead, the function maintains a connection to the lexical environment in which it was created.
When outer() is called, JavaScript creates a lexical environment for it. That environment contains the variable name:
The inner() function is created inside outer(), so it has access to that surrounding environment. When outer() returns inner, the function is stored in myFunction.
inner() needs the value of name. Since name is not inside its own environment, JavaScript looks through its surrounding environment and finds name in the environment created by outer().
This is the important part of a closure: the function retains access to the environment where it was created, even though the outer function has already finished executing.
You might think that once outer() finishes, everything created inside it should disappear. But inner() still has a reference to the environment containing name. Since that environment is still reachable through the function, JavaScript cannot simply remove it.
So conceptually, after outer() has finished, we can still think of the relationship like this:
The function and its connection to the surrounding environment together form the idea of a closure.
The word "closure" therefore describes the behavior where a function closes over the variables available in its surrounding lexical scope and continues to access them later.
To understand closures properly, it is useful to remember what lexical scope means.
Lexical scope means that the scope of a function is determined by where the function is written in the code, not where the function is called.
For example, inner() was written inside outer(), so its surrounding lexical scope includes outer().
This relationship exists before we even call the function. The function's position in the source code determines its lexical surroundings.
One of the most useful things about closures is that they allow a function to maintain state between calls.
Here, createCounter() finishes executing after returning the function. However, the returned function still has access to count.
Each time counter() is called, it accesses the same count variable and changes its value.
