Pregunta Javascript - alcance de anidado para el índice de bucle


Recuerdo que las variables tienen función de ámbito en Javascript. Pero, ¿cómo es el comportamiento si redefino la variable local en un bucle? Un caso de uso común son los bucles anidados.  En el siguiente código, si cambio j a i, el ciclo for externo termina después de una iteración, ya que el valor de i en el ámbito externo es el mismo que el ciclo interno para el ciclo. Como utilizo var, esperaba (similar a otro lenguaje) que se redefina dentro del ciclo FO interno. Significa esto en JS, no hay forma de redeclarar y usar variable local dentro del alcance de la función.

for (var i = 0, len = x.length; i < len; i++) {
            ...
            for (var j = 0, len = y.length; j < len; j++) {
                ...
            }
        }

5
2017-09-25 12:54


origen


Respuestas:


Como dijiste, JavaScript solo tiene función de alcance. Las declaraciones de variables se elevan a la parte superior del ámbito en el que se declaran. Tu ejemplo se interpreta así:

var i, j, len; //Declarations are hoisted...
for (i = 0, len = x.length; i < len; i++) { //Assignments happen in place
    for (j = 0, len = y.length; j < len; j++) {

    }
}

En cuanto a esta parte:

si cambio j por i, el bucle for externo termina después de una iteración

Si reemplazas j con i, luego después de la primera iteración del bucle interno, i estarán y.length - 1, y el bucle externo continuará o se detendrá, dependiendo de la diferencia entre x.length y y.length.

Si está interesado en la explicación real del funcionamiento interno, Especificación de ECMAScript (instanciación de unión de declaración) lo cubre en detalle. Para resumir, cada vez que el control entra en un nuevo contexto de ejecución, sucede lo siguiente (mucho más que esto sucede, pero esto es parte de él):

Para cada VariableDeclaration y VariableDeclarationNoIn d en código, en   orden de texto fuente hacer

  • Dejar dn ser el Identificador en re.
  • Dejar varAlreadyDeclared ser el resultado de llamar env de HasBinding concrete   paso del método dn como el argumento
  • Si varAlreadyDeclared es falso, entonces   
    • Llamada env de Método de concreto CreateMutableBinding pasando dn y    ConfigurableBindings como los argumentos.
    • Llamada env de SetMutableBinding   método concreto pasando dn, indefinido y estricto como los argumentos.

Esto significa que si declara una variable más de una vez por contexto de ejecución, será ignorada.


8
2017-09-25 12:57



Cada var declaración se colocará en la parte superior del alcance actual, por lo que su código es el mismo que:

   var i, j, len;
   for (i = 0, len = x.length; i < len; i++) {
        ...
        for (j = 0, len = y.length; j < len; j++) {
            ...
        }
    }

Mira esto: JavaScript de alcance y elevación


4
2017-09-25 12:57



No hay un ámbito de nivel de bloque en JS.

Pero si es necesario tener / volver a declarar el mismo nombre de variable en su código, puede hacer:

function loopIt(arr, fn, scope) {
    for (var i = 0, len = arr.length; i < len; i++) {
        fn.call(scope || this, arr[i], i, arr);
    }
}

Y úsalo como:

var firstArr = ["a", "b"];
var secondArr = ["c", "d"];

loopIt(firstArr, function(item, i) {
    var msg = "Hey it's '" + item + "'";
    console.log(msg);

    // if you want access to the parent scope's var
    var scopedItem = item;

    loopIt(secondArr, function(item, i) {
        var msg = "Hello it's '" + item + "' in '" scopedItem + "'";
        console.log(msg);
    });
});

Eso nos dará resultados de:

Hey it's 'a'
Hello it's 'c' in 'a'
Hello it's 'd' in 'a'
Hey it's 'b'
Hello it's 'c' in 'b'
Hello it's 'd' in 'b'

0
2017-09-25 13:46