2009-12-19 8 views
6

Me he encontrado con un problema muy extraño (para mí) con la palabra clave var. Lo reduje a un caso de prueba bastante mínimo, y encontré que se exhibió en Node.js (por lo tanto, V8 y Chrome), el inspector de Safari 4 (por lo tanto, Nitro) y FireBug (obviamente, SpiderMonkey). Originalmente estaba preparando un informe de fallas, pero dado que se muestra de manera tan amplia, supongo que no entiendo completamente cómo se supone que JavaScript debe abarcar y buscar variables.Operación confusa de la palabra clave `var` de JavaScript

El caso de prueba es muy pequeño, y en GitHub aquí: http://gist.github.com/260067. La única diferencia entre el primer y el segundo ejemplo es la inclusión de la palabra clave var.

Aquí, también, es un caso de prueba similar que presenta el mismo 'problema' de una manera diferente: https://gist.github.com/698b977ee0de2f0ee54a

Editar: necesidad, para evitar más respuestas que intentan explicar cómo funciona el alcance en cascada, I' Estoy íntimamente familiarizado con eso. Mi problema, es que no entiendo por qué el siguiente código 'funciona' (en el que alert() s 'exterior', seguido de 'interior', y luego otra vez 'exterior'):

(function(){ 
    var foo = 'outer'; 
    alert("Outer `foo`: " + foo); 

    (function(){ 
    foo = 'inner'; 
    alert("Inner `foo`: " + foo); 

    var foo; 
    })(); 

    alert("Outer `foo`: " + foo); 
})(); 

El var foo; ocurre en una posición completamente irrelevante para la reasignación de foo; Entonces, ¿por qué afecta esa tarea de una manera muy sustancial?

+0

¿Por qué está utilizando una evaluación? No hay absolutamente ninguna razón para usar eval en el código que ha publicado. – Marius

+0

Para demostrar el problema. La implementación real es muy diferente; Puedes verlo en la naturaleza aquí: http://github.com/elliottcable/poopy.js/blob/new-acquire/lib/from.js#L193 – ELLIOTTCABLE

+0

Tu último ejemplo funciona porque 1) foo = 'inner'; asigna el valor al ámbito padre foo, al que tiene acceso esta función. 2) no necesita usar var para declarar una variable. – Marius

Respuesta

14

El problema es que, a diferencia de otros idiomas, JavaScript crea todas las variables al inicio de una función. Esto significa que el código:

(function(){ 
    if(myVar == undefined){ 
     alert(myVar); 
    } 
    if(myVar == undefined){ 
     var myVar = 5; 
    } 
})(); 

es en realidad compilado e interpretado como

(function(){ 
    var myVar; 
    if(myVar == undefined){ 
     alert(myVar); 
    } 
    if(myVar == undefined){ 
     myVar = 5; 
    } 
})(); 

Para crear una variable y sólo tenerlo disponible dentro de un si o un lazo bloque, usted tiene que utilizar let, la cual es una nueva característica de JavaScript. No estoy seguro de cuántos navegadores lo implementan todavía (Firefox 3.5 lo hace si usa <script type="text/javascript;version=1.7">).

(function(){ 
    if(myVar == undefined){ 
     alert(myVar); 
    } 
    if(myVar == undefined){ 
     let myVar = 5; 
    } 
})(); 
+0

Sí, soy consciente de esto, ver mi respuesta a Amnon arriba. Mi confusión se debe al hecho de que afecta las llamadas desde * antes de definirse en el alcance local *. – ELLIOTTCABLE

+0

Sí, finalmente entendí tu pregunta y reescribí mi respuesta. Espero que esto ayude. – Marius

+0

Sí, eso ayudó bastante. Ver mi aclaración en la pregunta original. francamente todavía no puedo entender por qué sucede esto; Supongo que mi comprensión intuitiva de JavaScript, el lenguaje, no está en línea con la especificación/implementación. Independientemente, voy a marcar esta respuesta como 'aceptada'./= – ELLIOTTCABLE

1

la inclusión de var significa que la asignación de {} se realiza a las exportaciones de una variable local en lugar de a las exportaciones de variables globales, lo que significa que no tiene ningún efecto.

+0

Sí. Eso lo entiendo I * do * sé JavaScript básico. Mi problema es que viene * después de * la llamada que estamos buscando; no debería tener ningún efecto sobre si 'exports' no está definido en el momento de la llamada 'alert()'. Independientemente de lo que venga después, 'exports' * no * undefined en ese punto. – ELLIOTTCABLE

2

var exports no funciona exactamente como las variables locales en muchos idiomas. Declara exports como variable local en toda la función en lugar de solo el bloque adjunto (aunque aparezca después del primer uso), por lo que el argumento de la función con el mismo nombre está oculto.

Editar: la palabra clave let funciona de manera más convencional (declara una variable solo para el bloque contenedor) pero no está disponible en todas las versiones de JavaScript.

+0

Entonces, el intérprete lee adelante, y nota la declaración de la variable ... y la definición de la variable en el ámbito local (adjunta a 'undefined'), anula la del argumento? Eso es * extremadamente * contra-intuitivo. ¿Cómo es que el intérprete lee adelante en este caso? o.O – ELLIOTTCABLE

+1

Sí, es contrario a la intuición, pero así es ... En cuanto a cómo se hace, la función se analiza antes de ejecutarse. – Amnon

+0

"" "¿Cómo es que el intérprete lee adelante en esta instancia?" "" - mira hacia el futuro en CADA instancia. No es un "parse/interprete" línea por línea como en otros idiomas, el analizador lee TODOS los scripts antes de que comience a ejecutar cualquier cosa. – Hejazzman

Cuestiones relacionadas