In case of accessing the function variable before the declared scope, I would suggest that you do this in the function property, since it would become difficult or impossible to access the previously declared variable.
Instead of doing so:
function x() {
var a = 1;
function z() {
var a = 2;
}
}
It could be done like this:
function x() {
x.a = 1;
function z() {
z.a = 2;
console.log(x.a); // Imprime '1'
}
}
Generally, there are some special cases where you need to access a variable with a previous scope, to simulate something like static variables.
When there is this need, I usually use a self invoking function, with its declared variables, being accessed by a function in return.
Example:
var noMultihits = function ()
{
var timeout = 0;
return function (time, callback) {
// Sempre limpa o timeout anterior
// A variável é de outro escopo
clearTimeout(timeout);
timeout = setTimeout(callback, time)
}
})();
noMultihits(500, function (){});
noMultihits(500, function (){});
noMultihits(500, function (){});
// Só executa o último, pois a variável é do escopo da funçao autoexecutável
The advantage of this is:
-
Do not pollute the global scope.
-
If it does not pollute the global scope, there is no risk of collision of variable names.
Still using the self invoking functions, you can join the two solutions to use something that I would call an anonymous object.
var ajaxInfinito = (function anonimo()
{
anonimo.pagina = 1;
return function () {
console.log(anonimo.pagina);
$.ajax({
url: 'pagina',
data: {pagina: anonimo.pagina},
success: function () {
anonimo.pagina++
}
});
}
})()
ajaxInfinito(); // 1
ajaxInfinito(); // 2
ajaxInfinito(); // 3
ajaxInfinito(); // 4
ajaxInfinito(); // 5
console.log(anonimo); // undefined, só existe no escopo da self-invoking
In this case we will make important observations:
-
ajaxInfinito
will only receive the value of the function that is in return
of expression anonimo
.
-
anonimo
is not a statement of a function, but an expression. I would call this a named closure. Note that console.log
in anonymous will say that the variable does not exist. This is because this name is only valid within the scope of the self-executing function.
-
As we are in another scope, the value of anonimo.pagina
will always increment with each call, since it is part of the scope of the auto-executable function whose internal name is anonimo
.
If you need to simplify access to anonimo
values, you could use the with .
See:
var soma = (function obj(){
obj.y = 4;
obj.z = 5;
return function () {
var x = 3;
with(obj) {
x += y;
x += z;
}
return x;
}
})();
soma(); // 12
Context change
@GuilhermeLautert commented on this
usage. It is not possible to use it directly, since the context of the functions when they are called is window
. Only when they are instantiated does this
refer to the object itself.
What can be done is to change the context in which this
is used by the function, passing other values. This is done using the call
method.
Example:
function nome (pronome) {
return pronome + ':' + this.a + ' ' + this.b;
}
nome.call({a : 'Wallace', b : 'Souza'}, 'Senhor'); // Senhor: Wallace Souza
nome.call({a : 'Guilherme', b : 'Lautert'}, 'Mister'); // Mister: Guilherme Lautert
The function $.proxy
of jQuery does something similar, but it is something that already exists natively.