JavaScript - Variable access

14

Situation

I'm deepening my JavaScript study, and I had a small question. At closure , encapsulation and variable scope , all show how to use var and talk about Local and Global scopes, however in all the examples I've seen always use variables with names other than media that "descends".

Example

function x() {              // "x" tem acesso a "a"
    var a;
    function y() {          // "y" tem acesso a "a" e "b"
        var b;
        function z() {      // "z" tem acesso a "a", "b", e "c"
            var c;

Doubt

How to access the variable of "parent" when it exists in place?

Example

function x() {              // "x" tem acesso a "a"
    var a;
    function y() {          // "y" tem acesso a "x.a" e "a"
        var a;
        function z() {      // "z" tem acesso a "x.a", "x.y.a", e "a"
            var a;

Test

When the variable is global () I can do this:

var a = 'Global';
function(){
    var a = 'Local';
    console.log(window['a']);
    console.log(a);
}
    
asked by anonymous 28.10.2015 / 15:03

2 answers

11

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.

    
28.10.2015 / 15:28
7

When you define a local variable with the same name as a higher-scoped variable, the local variable overwrites access to a larger-scope variable.

One way around this would be to associate the variable with the function instance. Example:

function alfa()
{
  alfa.a = "valor em alfa.a";

  function beta() {
    var a = "valor de a local";
    console.log(alfa.a);
  }
  beta();
}

alfa();

But this type of code stinks and it would be recommended to use different names for that purpose.

    
28.10.2015 / 15:32