How do Closures work in Javascript?

Asked

Viewed 9,611 times

124

I always wanted to know how Closures work in Javascript, I’ve read some settings but never understood very well.

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

  • 2

    FWIW an article about me: http://epx.com.br/artigos/closure.php

5 answers

83

Closure ("enclosure" in English, but this term is rarely used), refers to how functions defined within a "lexical context" (i.e. the body of a function, a block, a source file) access variables defined in this 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 within (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 internal function will perform, nor what value the external variables had at the time when the object function was created (in contrast to the function definition, which is at compile/interpretation time). What matters is that both share the same variable, and written on one side will reflect on the readings on the other and vice versa.

Pitfalls

An example of 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 external context - which means that when the i external changes, the value the internal function will access is different. At the end, i will equal elementos.length (ex.: 10), so that clicking on any element will always print "This is element 10".

A possible solution to this problem is the creation of 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 function parameter is not the same i used by the loop for - and he owns the value that the variable had at the time of execution.

Usefulness

There are many advantages to using closures, as exemplified in @Jordan’s reply (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 as there is no direct reference to privado, this object cannot be manipulated directly (only indirectly through foo and bar). But how 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, quoted in an article of Paul Graham (in English) where the power of relative expressiveness of the various programming languages is discussed. The requirement is simple:

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

Note: (a) [argument] is a number, not an integer. (b) is incremented of, nay 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 manly (requiring too much code to do too much), so that they take longer to be written, read, may contain more bugs (since the likelihood of bugs increases with the amount of line code), etc.


Note: I included here part of an answer I gave for 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.

  • 1

    /* Even "a" for script1.js, script2.js, etc (effectively, a global one)*/ Dexa see if I understand, that means if I declare a variable : var a = "Globlal"; and save this file as meuscript.js and later I have a script1.js file, this variable will be accessible by the script1.js file, even if it is located in the meuscript.js file? pls need to understand...

  • 2

    @Magichat Yes. If both scripts are included on the same page, script1.js can access the variable a defined by meuscript.js normally (assuming that it has been defined in top-level, as in the example). That’s why many libraries - like jQuery - put the entire script inside a (function() { ... })();, not to create global variables without need (or worse, when the global ones of one script overwrite the global ones of another script).

  • Vlw man... I’ll stay tuned..

  • @mgibsonbr this ap is off line since 2014, so the question is without an answer accepted forever?

  • @durtto yes, it gets.

51

"Closures" (something like "closing") are functions that "capture" variables coming from outside the function. In English it is said that a "closure" close-ups over (closes on) 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);

44

What is closure?

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

This technique comes from functional languages, but was eventually disseminated 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 the function display has access to variable message, but note that the variable was declared in the parent function body start. The function "from within" (Inner) has access to the variables of "function outside" (Outer). display in the example is considered a closure.

But even more, the referenced variables of the parent function remain available even at the end of its execution. Here is another example:

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) have already completed its execution.

How it works

In order for this to be possible the language has to provide function not only to references of its local variables and global variables but also to references of the variables nonlocal, that are neither in its scope nor in the global scope, but that somehow became accessible to it (as in the example by the function that encapsulates it).

Speaking of Javascript, in practice, this "environment" of the function is called Execution context. For each function call the interpreter assembles a Execution context to her, 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 its scope ends, which is usually how the execution comes out of the block encapsulating it ({ }).

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

Note: this stack is not the same memory we call "stack" (stack) in other languages like C/C++.

Reference, not value

As you may have noticed from most of the examples out there, with closure a copy of the references variables, and not their values.

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

30

Closure has to do with scope of a Javascript variable.

To avoid polluting the global namespace by protecting the variables in your script from mixing with other variables in other scripts, you can use a large closure to put all the code in your plugin, app, or library...

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

The scope of a closure will always get started with the character { and end with the character }. Yes, that’s right: a scope (closure) always has a beginning and an end determined by the bracket opener and bracket closer.

What’s interesting is that by creating a function at a certain point in the code, you automatically create a closure, where current local variables are 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;
})();

Note the variable accountant. We don’t have access to it "outside" of the module crud. And it was also not defined within the function update. When we call crud.update() for the first time, the variable accountant will come true 1. If we call crud.update() for the second time, the variable accountant will come true 2.

You wanted a simple and objective answer: look at the example above. If you understand the simple fact that we have a captured variable within a scope, but always available for the function that "captured" you will have understood the essence of the riddle. It’s not complicated. But it’s a Feature Javascript Making Room for Amazing Patterns.

1

Closure, in JS, for example - let me give you an example of a language - is when the outer scope is seen and guarded, from within a block or inner 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 that block above, minhaUrl contains "Produtos/1" and it’s clear to watch.

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 code above, when I click the Request 4 button, I change the value of minhaUrl. Next, if I press the Ajaxeira button, will appear the popup with the contents of request and no more than product, which is the standard.

Note also that I’m here using pedidos4() and ajaxeira() as callbacks and these also see and keep the scope immediately external to their statements.

  • Your edition greatly improved the answer. The first time I read it, in the first version, I was very confused

  • Thanks @Jeffersonquesado, I was a little suspicious that nobody would understand :D

Browser other questions tagged

You are not signed in. Login or sign up in order to post.