Functions and their references to a lexical environment are bundled together to form a closure. In other words, closures allow you to access the outer function's scope from within an inner function. In JavaScript, closures are created each time a function is created. Essentially, closures act as a bridge that connects the internal and external parts of a function.
To define a closure, you first need a function to enclose an anonymous function. Closures require the use of local variables, as defining them with global variables would defeat the purpose of using closures. The outermost function defines a local scope to allow the definition of local variables that cannot be directly accessed from outside the function.
As seen, the name
variable defined within the function is not destroyed and can still be accessed from outside the function. By using closures, local variables can be kept in memory, thereby avoiding the use of global variables. Global variable pollution can lead to unpredictability in applications, as every module that can access them is likely to cause issues.
Closures share the same function definition but hold different lexical environments.
In object-oriented languages like Java and PHP, it is possible to define private members that can only be accessed within the class and not by external classes. While JavaScript does not inherently support private members, they can be simulated using closures. Private methods not only serve to restrict access to the code but also provide powerful management of the global namespace, preventing non-core methods from cluttering the public interface of the code.
Closures in JavaScript provide support for the callback mechanism, where a closure is not released even if the function is not immediately called. In JavaScript, it is valid to pass a callback
function as a parameter to other functions or to return it as a value for later use.
In this example, the callback
function and its lexical environment form a closure. The variable localVal = 1
within the lexical environment of the function callback
is not immediately released when the callback function is passed and can still be used when the callback is executed, demonstrating how closures support the callback mechanism.
Prior to the introduction of the let
keyword in ECMAScript 2015, only function scope and global scope were available, and functions could be nested within other functions to create local scopes. However, the for
loop did not have a local scope, leading to a common problem of creating closures.
The output is 3 3 3
, instead of the expected 0 1 2
. This is because when these three closures are created within the loop, they share the same lexical scope. As i
is declared using var
, due to variable hoisting and function scope, when the closure functions are executed, the loop has already finished, and i
has been assigned the value of 3
. As a result, it prints as 3 3 3
.
let
keywordMemory leaks refer to the situation where variables that are no longer in use (or accessible) still occupy memory space and cannot be reused.
The variables referenced by closures should be needed and should not cause memory leaks. However, in the JScript.dll
engine used in IE8
, there are some issues causing memory leaks.
For specific behaviors of closure memory reclamation in various engines, please refer to this article.
It is not wise to create functions within other functions unless it is necessary for certain specific tasks, as closures have a negative impact on script performance in terms of processing speed and memory consumption.
When creating new objects or classes, methods should usually be associated with the object's prototype rather than defined within the object's constructor. This is because doing so will cause the method to be reassigned each time the constructor is called.