"Disclosure" a closure

8

I understand the great powers and the great consequences of closures .

But suppose I have the following code ...

function foo () {
    var x = 1;
    function bar () {
        return x++;
    }
    return bar;
}

... And I do not want to keep the context of foo in memory, because in real life it may be a function (or several) that uses a very large amount of memory. But I still want to use the values processed by foo in the context of bar .

If it were x a global variable, would it still form a closure? If x was external to foo , as in ...

var x = 1;
function foo () {
    function bar () {
        return x++;
    }
    return bar;
}

... Would there still be a closure?

Is there any sane way to achieve the goal I described earlier? And regardless of that, is there any way to destroy an execution context that I no longer need to use?

    
asked by anonymous 30.01.2014 / 14:24

3 answers

6

As I understand it, you need part of variables in a given execution context, but you do not want to keep all in memory. One solution is to generate your function in another context, passing as a parameter the data you want to keep:

function foo () {
    var x = 1;
    var naoQuero = 2;
    return criaBar(x);
}
function criaBar(x) {
    return function() {
        return ++x;
    }
}
var bar = foo();
bar(); // retorna 2
bar(); // retorna 3

But be aware: the x within the returned function will be a copy of the original, when it was passed to criaBar . It's no use trying to change it within foo , after calling criaBar , and waiting for bar() to increment this changed value.

And notice that I changed the return x++ to return ++x , otherwise the code returns the current value and then increments, and I imagine the goal is to return the already incremented value.

    
30.01.2014 / 14:49
4

JavaScript (JS) does not have explicit memory management, the browser decides when to clean it. Sometimes a loss of efficiency in rendering JS may occur due to a garbage collection (GC) break.

There are techniques for overcoming failures caused by GC.

Suppose you have an algorithm written in JS, and every second you are creating a new object, it is obvious that after a certain amount of time the GC will act to free up more space for your application.

For real-time applications that require a lot of space, the simplest thing you can do is to reuse the same memory. It depends on how you structure your code. If it generates a lot of junk, then it may over time experience a slowdown caused by GC. Here, I list 3 initial items to improve your code.

Use simple procedures: Whenever possible, you should try to reuse the same object by adding or modifying its properties. Object recycling is a very good way to avoid creating new objects by filling in the "memory" of the browser.

In case of an array: it is usually assigned [] in order to remove it from memory, but it is a mistake as it creates a new array and leaves the old one as garbage. To reuse the same array you must use vararray.Length = 0 This has the same effect as the previous one but reuses the array object instead of creating a new one. You can still use the delete operator which I will explain below.

In case of functions: Sometimes it is necessary to call a specific function at a certain time or at intervals using setInterval or setTimeout.

setTimeout(function() { function(){ ... código ... } }, 10);

You can optimize this code by assigning the function to a permanent variable rather than creating it at each interval.

var minhafuncao = function(){ ... código ... }
setTimeout(minhafuncao, 10);

Be careful when using the functions slice() it creates a new array leaving the previous one untouched, substr() also leaves the initial string intact, generating a new one in the "memory", there are still others ) that generate new objects leaving the previous ones occupying space, forcing the GC to come into activity more often.

You still have the option to use the delete that serves to remove properties from objects:

x = 42;         // craindo uma propriedade C do objeto global
var y = 43;     // declarando uma nova variável 'y'
meuObj = {
    h: 4,
    k: 5
};

delete x;        // retorna true  (x é uma propriedade do objeto global e pode ser deletado)
delete y;        // retorna false (delete não funciona com variáveis)
delete Math.PI;  // retorna false (delete não funciona com propriedade pré definidas)
delete meuObj.h; // retorna true  (propriedade definida por usuário pode ser deletada)

delete meuObj;   // retorna true  (meuObj é uma propriedade do objeto global, não é uma variável, nesse caso pode ser deletado)

Another example now using prototype

function Foo(){}
Foo.prototype.bar = 42;
var foo = new Foo();
delete foo.bar;           // retorna true, mas não tem efeito, bar é uma propriedade herdada
console.log(foo.bar);     // mostra 42, propriedade herdada
delete Foo.prototype.bar; // deleta propriedade no prototype
console.log(foo.bar);     // mostra "undefined"

Regarding array when you remove an element, the length of the array is not affected. This is true even if you delete the last element. When the delete operator removes an element from the array, that element is no longer accessible. In the following example, myArray [3] is removed with delete.

var meuArray= ["zero","um","dois","três","quatro","cinco"];

delete meuArray[3];
if (3 in meuArray) {
    //esse bloco nunca será executado
}

If you want an array element to exist, but only have an undefined value, use undefined instead of the delete operator. In the following example, myArray [3] is assigned undefined , but the array element still exists:

var meuArray= ["zero","um","dois","três","quatro","cinco"];

meuArray[3]=undefined;
if (3 in meuArray) {
    // esse bloco será executado
}

Avoiding junk in JS is an art, I would say it is (at least today) impossible, but browsers have evolved to improve the collage of these. What we have to keep in mind is that all code must be done in order to optimize system performance so that after thousands of lines it is not necessary to redo it.

    
30.01.2014 / 15:45
3

Yes, do not use closures. Use simple objects with NEW or literal objects with {}. The closure, by definition will maintain the entire scope: the internal + external function.

Your second solution is even worse, because it will ensure that the object has reference to the 'global' variable x, not allowing the GC to enter it to clear it from memory.

    
30.01.2014 / 14:38