How do closures work in JavaScript?

I've always wanted to know how Closures work in JavaScript, I've read some definitions but never understood very well.

Could you give me a simple, objective but content explanation?

Author: viana, 2014-01-11

5 answers

Closure ("clausura" in English, but this term is rarely used), refers to the way functions defined within a "lexical context" (i.e. the body of a function, a block, a source file) access variables defined in that context.

In JavaScript, only functions define a new lexical context (other languages have different rules - some even support the concept of closure):

var a = 10; // Mesmo "a" para script1.js, script2.js, etc (efetivamente, uma global)
function f() {
    var b = 20; // Um "b" diferente para cada invocação de f
    if ( x ) {
        var c = 30; // Mesmo "c" dentro e fora do if (i.e. o contexto é "f", não o bloco if)

And each new context created inside (inner ) of an existing context has access to all variables defined in the "outside" ( outer):

function x(a1) {          // "x" tem acesso a "a"
    var a2;
    function y(b1) {      // "y" tem acesso a "a" e "b"
        var b2;
        function z(c1) {  // "z" tem acesso a "a", "b", e "c"
            var c2;

It is important to note that it does not matter when the inner function will execute, nor what value the outer variables had at the time the object function was created (in contrast to the function definition, which is at compile/interpret time). What matters is that they both share the same variable, and written on one side will reflect on the readings of the other and vice versa.

Pitfalls

An example of a common error involving closures is the creation of a function within a block for :

for ( var i = 0 ; i < elementos.length ; i++ ) {
    elementos[i].onclick = function() {
        alert("Esse é o elemento " + i);
    }
}

This code does not work as expected, since the variable i used by the anonymous function is the same i as the external context - meaning that when the external i changes, the value that the internal function will access is different. In final, i will be equal to elementos.length (e.g. 10), so clicking on any element will always print "this is Element 10".

A possible solution to this problem is to create a new lexical context that "captures" the value of that variable at the desired time:

for ( var i = 0 ; i < elementos.length ; i++ )
    (function(i) {
        elementos[i].onclick = function() {
            alert("Esse é o elemento " + i);
        }
    })(i);

Thus, the i parameter of the function is not the same i used by the loop for - and it has the value that the variable had at the time of execution .

Utility

There are many advantages to using closures , as exemplified in @Jordan's answer (which demonstrates a means of implementing currying). Another example would be to simulate private variables - something that is not normally supported by the JavaScript language:

function MeuObjeto() {
    this.publico = { ... }
    var privado = { ... }
    this.foo = function() {
        return privado.a;
    }
    this.bar = function(x) {
        privado.a = x;
    }
    ...
}
var obj = new MeuObjeto();
obj.publico; // Acessível
obj.privado; // undefined

Note that since there is no direct reference to privado, this object cannot be manipulated directly (only indirectly through foo and bar). But since foo and bar were created within the constructor's lexical context, they have access to the constructor's local variables and can access them normally.

Another "classic" example is the Accumulator Generator, cited in an article by Paul Graham (in English) where the power of relative expressiveness of various programming languages is discussed. The requirement is simple:

Write a function foo that receives a number n and returns a function that receives a number i, and returns n incremented by i.

Note: (a) [the argument] is a number, not an integer. (b) is incremented by, not plus.

The proposed solution, with examples of use:

function foo (n) { 
    return function (i) { 
        return n += i;
    } 
}

var x = foo(10);
x(2); // 12
x(3); // 15

var y = foo(20);
y(5); // 25
y(2); // 27

As the examples at the end of the article show, languages that do not support closures end up being much more varbose (requiring a lot of code to do bit), so that they take longer to be written, read, may contain more bugs (since the probability of bugs increases with the amount of line of code), etc.


note: I included here part of an answer that I gave to a similar question (the question was not about closures, but the root cause of the problem was), adapting for the answer to become more generic.

 81
Author: mgibsonbr, 2020-06-11 14:45:34

" Closures "are functions that" capture " variables that come from outside the function. In English it is said that a" closure " closes over (closes over) certain variables.

A typical example:

function somador(v1) {
  return function(v2) {
    return v1 + v2;
  }
}

somador returns a closure, a function that captures the value of v1 (note that somador is not a closure, but its return value):

var soma10 = somador(10);
var total1 = soma10(5); // total1 é 15, já que soma10 capturou o valor de v1 como "10"

var soma20 = somador(20);
var total2 = soma20(5); // total2 é 25, soma20 capturou v1 = 20

var total3 = somador(30)(5); // usando diretamente a "closure"

"Currying" is a function that "captures" some parameters for other functions and returns a function (a "closure") that accepts the rest of the parameters.

Given the function soma:

function soma(v1, v2) {
  return v1 + v2;
}

And a simple "currying" function:

function curry(fn /*, argumentos parciais para fn */) {
  var args1 = [].slice.call(arguments, 1); // argumentos após fn
  return function(/* o resto dos argumentos para fn */) {
    var args2 = [].slice.call(arguments);
    return fn.apply(null, args1.concat(args2)); // junta todos os argumentos
  }
}

We can use them like this:

var soma10 = curry(soma, 10); // soma10 capturou "soma" e "10"
var total = soma10(5);
 50
Author: Jordão, 2014-01-11 03:51:18

What is closure ?

Closure is a programming language concept that, in a simplified way, allows a function to access variables from its parent function.

This technique comes from functional languages, but was eventually widespread and implemented also for other languages such as JavaScript and C#.

Example:

function start() {
    var message = "hello world";

    function display() {
        console.log(message);
    }

    display();
}

In the example function display has access to variable message, but note that the variable has been declared in the parent function body start. The function "inside" (inner) has access to the variables of the "outside function" (outer). display in the example is considered a closure.

But even more so, the referenced variables of the parent function remain available even at the end of their execution. Another example follows:

function getDisplay() {
    var message = "hello world";    
    return function display() {
        console.log(message);
    };
}

var display = getDisplay();
display();

Note that now the display of the value of message is done even after your function (getDisplay) has already finished its execution.

As works

For this to be possible the language has to provide for function not only the references of its local variables and global variables but also the references of the Non-Local variables, which are neither in its scope nor in the global scope, but which have somehow become accessible to it (as in the example by the function that encapsulates it).

Speaking of JavaScript, in practice, this function" environment " is called execution context. For each function call the interpreter mounts a execution context to it, and that's where the magic happens : -)

But what about the garbage collector ?

Traditionally, the memory used by the variable is "released" to the garbage collector as soon as it ends its scope, which is usually how the execution exits the block that encapsulates it ({ }).

The difference in JavaScript is that your interpreter keeps a stack of execution context as functions are called. And it is this stack that will provide the interpreter with the information whether the scope of the variable has ended or not.

It is worth leaving the Note: This stack is not the same memory that we call "stack" (stack) in other languages like C/C++.

Reference, not value

As you may have noticed by most of the examples out there, with closure the copy of the References of the variables is made, and not of its values .

This means that by changing the value of a variable within a closure all other contexts that have reference to that variable will get this value when accessing it. Beware of any side effects.

 42
Author: talles, 2014-01-11 03:31:13

Closure has to do with the scope of a variable in JavaScript.

In order not to pollute the global namespace, protecting that the variables of your script mix with other variables of other scripts, you can use a large closure to put all the code of your plugin, app, or library...

(function($){
    //  aqui vem o teu código
    var contador;
})(jQuery);

The scope of a closure will always Start with the character { and end with the character }. Yes, that's right: a scope (closure) always has a start and end determined by the bracket opener and bracket closer.

What's interesting is that when you create a function at a given point in the code, you automatically create a closure , where the current local variables become available within the new scope:

var crud = (function(){
    var modulo = {},
        contador = 0;

    modulo.update = function() {   // aqui temos o início de outro closure
        contador++;
    };  // e aqui o respectivo final

    return modulo;
})();

Look at the variable counter . We do not have access to it "from the outside" of the module crud . And it was also not defined inside the Update function. When we call cruel.update () for the first time, the variable counter will change to 1. It's called crud.update () for the second time, the variable counter will change to 2.

You wanted a simple and objective answer: take a good look at the example above. If you understand the simple fact that we have a variable captured within a scope, but always available to the function that "captured" it, you will have understood the essence of the riddle. It is not complicated. But it's a JavaScript feature that makes room for amazing patterns.

 30
Author: J. Bruni, 2014-02-06 16:31:26

Closure, in JS, for example - I'll give an example of a language-is when the outer scope is viewed and saved, from within an inner block or function.

For example,

var minhaUrl = "Produtos/1";

function ajaxeira() {
  $.ajax({
    url: minhaUrl,
    ...
    success: function (data) {
      alert(JSON.stringify(data));
    }
  });
}

At the beginning of the execution of this block above, minhaUrl contains "Produtos/1" and it is clear when observing it.

For illustration purposes, I can demonstrate the use of this function ajaxeira() and change minhaUrl as if it were within the scope of the function,

minhaUrl = "Pedidos/4";
ajaxeira(); // Imprime o pedido 4 em formato JSON, em um alert, se der boa

minhaUrl = "Produtos/11";
ajaxeira(); // Imprime o produto 11 em formato JSON, em um alert, se der boa

In the above case, minhaUrl is a global variable, but I can have a function that houses var minhaUrl and, within this function, have another function, which uses minhaUrl:

$(function () {
    var minhaUrl = "Produtos/1";
    
    function ajaxeira() {
        alert('Imagine aqui a chamada ajax para ' + minhaUrl);
    }
    
    function pedidos4() {
        minhaUrl = "Pedidos/4";
    }
    
    $('#btnPedidos4').on('click', pedidos4);
    $('#btnAjaxeira').on('click', ajaxeira);

    alert(minhaUrl); // Popup com 'Produtos/1'
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<input type="button" id="btnAjaxeira" value="Ajaxeira" />
<input type="button" id="btnPedidos4" value="Pedidos 4" />

In the above code, when I click Request button 4, I change the value of minhaUrl. Next, if I hit the Ajax button, it will pop up with the contents of the request and no more of the product, which is the default.

Also Note that I'm here using pedidos4() and ajaxeira() as callbacks and these they also see and store the scope immediately outside their statements.

 1
Author: Marcelo Shiniti Uchimura, 2018-07-10 15:03:56