This is a translation from the community wiki .
In JavaScript, functions can be described not only one after another, but one inside the other. When you have one function inside another, then the internal function has access to the variables of the external function.
function внешняя(x) { var tmp = 3; function внутренняя(y) { alert(x + y + (++tmp)); // выведет 16 } внутренняя(10); } внешняя(2);
This code always gives 16, because the внутренняя
function sees x
, which is a variable in the внешняя
function. In this case, the function argument. Also внутренняя()
can see tmp
from внешней()
.
This is called closure or closure. More precisely, the closure is called an external function, and everything inside it is called a closure environment or closure environment.
It is sometimes said that a closure is a function that returns a function, this is wrong, in order to call a function closure enough that the internal function accesses a variable from outside its scope.
function foo(x) { var tmp = 3; return function (y) { alert(x + y + (++tmp)); // will also alert 16 } } var bar = foo(2); // bar is now a closure. bar(10);
The above function also gives 16, because bar
even after completion of foo
continues to have access to x
and tmp
, even if the bar
variable itself is not inside the scope in which they were declared.
However, since the tmp
variable is still inside the closure of bar
, it continues to increase with each call to bar
.
Here is the simplest closure example:
var a = 10; function test() { console.log(a); // вывод 10 console.log(b); // вывод 6 } var b = 6; test();
When a function is started in JavaScript, an environment is created for it, that is, a list of all the variables visible to it, not only the arguments and variables declared inside it, but also outside, in this example it is 'a' and 'b'.
You can create more than one closure in one environment, returning them as an array, an object, or linking them to global variables. In this case, they will all work with the same x
or tmp
value, without creating separate copies.
Since in our example x
is a number, its value is copied to foo
as its argument x
.
JavaScript, on the other hand, always uses links when passing objects. If you called foo
with an object as an argument, then the returned closure would return a reference to the original object!
function foo(x) { var tmp = 3; return function (y) { alert(x + y + tmp); x.memb = x.memb ? x.memb + 1 : 1; alert(x.memb); } } var age = new Number(2); var bar = foo(age); // bar теперь замыкание ссылающееся на age. bar(10);
As you might expect, each call to bar(10)
increases x.memb
. What you might not expect is that x
continues to refer to the same object as age
! After two calls to bar
, age.memb
will be equal to 2! By the way, this is how memory leaks occur in HTML objects.