Pregunta Sorprendido de que la variable global tiene un valor indefinido en JavaScript


Hoy, me sorprendí por completo cuando vi que una variable global tiene undefined valor en cierto caso.

Ejemplo:

var value = 10;
function test() {
    //A
    console.log(value);
    var value = 20;

    //B
    console.log(value);
}
test();

Da salida como

undefined
20

Aquí, ¿por qué el motor de JavaScript está considerando el valor global como undefined. Sé que JavaScript es un lenguaje interpretado. ¿Cómo es posible considerar variables en la función?

¿Es eso una trampa del motor de JavaScript?


73
2018-01-31 19:43


origen


Respuestas:


Este fenómeno se conoce como: Elevación de JavaScript de la variable.

En ningún momento accedes a la variable global en tu función; solo estás accediendo al local value variable.

Tu código es equivalente a lo siguiente:

var value = 10;

function test() {
    var value;
    console.log(value);

    value = 20;
    console.log(value);
}

test();

Todavía estoy sorprendido de que estés recibiendo undefined?


Explicación:

Esto es algo en lo que cada programador de JavaScript se topa tarde o temprano. En pocas palabras, cualesquiera variables que declares son siempre izada a la cima de su cierre local. Entonces, a pesar de que declaró su variable después de la primera console.log llamada, todavía se considera como si lo hubiera declarado antes de eso.
Sin embargo, solo se está izando la parte de declaración; la asignación, por otro lado, no lo es.

Entonces, cuando llamaste por primera vez console.log(value), estabas haciendo referencia a tu variable declarada localmente, que aún no tiene asignada nada; por lo tanto undefined.

Aquí está otro ejemplo:

var test = 'start';

function end() {
    test = 'end';
    var test = 'local';
}

end();
alert(test);

¿Qué crees que esto alertará? No, no sigas leyendo, piensa en ello. ¿Cuál es el valor de test?

Si dijiste algo más que start, te equivocaste. El código anterior es equivalente a esto:

var test = 'start';

function end() {
    var test;
    test = 'end';
    test = 'local';
}

end();
alert(test);

para que la variable global nunca se vea afectada.

Como puede ver, no importa dónde coloque su declaración de variable, siempre es izada a la cima de su cierre local.


Nota al margen:

Esto también se aplica a las funciones.

Considerar esta pieza de código:

test("Won't work!");

test = function(text) { alert(text); }

que le dará un error de referencia:

Unloading ReferenceError: la prueba no está definida

Esto arroja a muchos desarrolladores, ya que esta pieza de código funciona bien:

test("Works!");

function test(text) { alert(text); }

La razón para esto, como se dijo, es porque la parte de asignación es no izada Entonces en el primer ejemplo, cuando test("Won't work!") se ejecutó, el test variable ya ha sido declarada, pero aún no tiene la función asignada.

En el segundo ejemplo, no estamos usando asignación de variable. Por el contrario, estamos utilizando la sintaxis de declaración de función adecuada, que hace obtener la función completamente izada.


Ben Cherry ha escrito un excelente artículo sobre esto, apropiadamente titulado JavaScript Scoping y elevación.
Léelo. Te dará una imagen completa con todo detalle.


155
2017-08-28 23:39



Me decepcionó un poco que se explicara el problema aquí, pero nadie propuso una solución. Si desea acceder a una variable global en el alcance de la función sin la función que hace primero una var local indefinida, haga referencia a la var como window.varName


41
2018-01-31 19:45



Las variables en JavaScript siempre tienen un alcance para toda la función. Incluso si se definieron en el medio de la función, son visibles antes. Fenómenos similares pueden observarse con el levantamiento de funciones.

Dicho esto, el primero console.log(value) ve el value variable (la interna que sombrea el exterior value), pero aún no se ha inicializado. Puede pensar que todas las declaraciones de variables se movieron implícitamente al principio de la función (no bloque de código más interno), mientras que las definiciones se dejan en el mismo lugar.

Ver también


10
2018-01-31 19:47



Hay una variable global value, pero cuando el control ingresa al test función, otra value se declara la variable, que sombrea la global. Dado que las declaraciones variables (pero no asignaciones) en JavaScript se elevan a la parte superior del ámbito en el que se declaran:

//value == undefined (global)
var value = 10;
//value == 10 (global)

function test() {
    //value == undefined (local)
    var value = 20;
    //value == 20 (local)
}
//value == 10 (global)

Tenga en cuenta que lo mismo es cierto para las declaraciones de funciones, lo que significa que puede llamar a una función antes de que parezca estar definida en su código:

test(); //Call the function before it appears in the source
function test() {
    //Do stuff
}

También vale la pena señalar que cuando se combinan los dos en una expresión de función, la variable será undefined hasta que se realice la tarea, por lo que no puede llamar a la función hasta que eso suceda:

var test = function() {
    //Do stuff
};
test(); //Have to call the function after the assignment

3