2012-01-30 12 views
7

Fuera de simplemente curiosidad intelectual, ¿por qué Javascript a aceptarJavascript: z = z || [] arroja un error cuando no se usa VAR, ¿por qué?

var z = z || []; 

para inicializar z (como z puede definida inicialmente)

pero sin var, se emite un error (en el espacio global)

z = z || []; 

(si z está previamente definido)

en el espacio global que no están obligados a utilizar VAR aunque lo entiendo podría b e mala práctica.

Antes de decir esto es un duplicado de preguntas como

What is the purpose of the var keyword and when to use it (or omit it)?

nota de la declaración que "Si estás en el ámbito global, entonces no hay diferencia."

Obviamente no es 100% cierto, dado mi ejemplo de trabajo.

¿Es esto un capricho o existe una lógica legítima?


añadiendo un resumen de la respuesta como lo he aprendido:

Gracias a Tim (véase más adelante) la clave de mi malentendido no se dan cuenta de esto (fundamental de Javascript)

var z; no hace absolutamente nada si z ya existe

Así es como esta expresión parece tener ambas formas, si asume incorrectamente que "var z" siempre se inicializa.

Comenzando por la izquierda, "var z" simplemente se asegura de que z esté definido pero en realidad no afecta a ningún valor existente si ya existe. Luego, a la derecha, si z ya existe, se usa, si no, la variable acaba de declararse (pero vacía) por lo que no se utilizará, pero no arrojará un error.

Este es un excelente artículo sobre este tipo de determinación del alcance y de elevación tema en Javascript: http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting

Muchas gracias a MiniTech y todos los demás que contribuyeron también!

+2

Como regla general: copiar el mensaje de error real normalmente es más útil que simplemente escribir "arroja un error". –

Respuesta

6

z = z || [] arrojará en cualquier ámbito (global o no) donde no hay z en la cadena de alcance. La razón de esto es que la expresión primero intenta recuperar el valor de una variable existente llamada z en el lado derecho, que es un error cuando no existe.

La razón por la var z = z || [] no lanza un error es que se crea la variable z (si no existe ya) antes de ejecutar la expresión, un efecto conocido comúnmente como de elevación.

Por otro lado, la asignación de un valor a un identificador no resuelto (por ejemplo, z = 2) funcionará sin error en cualquier ámbito (excepto en el modo estricto ECMAScript 5, que lo prohíbe y arroja). Si el identificador no se puede resolver, se agregará como una propiedad del objeto final en la cadena de alcance, que es el objeto global, por lo tanto, dando la apariencia de crear una variable global.

+0

Ah, creo que lo entiendo. Entonces, "var z" se hace primero en el lado izquierdo, como instruir "crear una nueva z", pero luego busca una "vieja z" en el lado derecho. En ese orden, "z" acaba de inicializarse a la izquierda, por lo que la "z" en el lado derecho no está indefinida, aunque está vacía. Sin la var, "z" a la derecha no está solo vacía, no está definida. Mmm, está bien, si "var z" lo define como nuevo a la izquierda, ¿cómo conserva este código los valores existentes? Parece que tiene ambas formas, se inicializa a la izquierda para la derecha, pero también puede mantener el valor a la derecha. –

+0

@ck_: Sí, creo que lo tiene, aunque la terminología necesita cierto cuidado porque 'undefined' es un valor real en JavaScript y, de hecho, es el valor predeterminado asignado a una variable (por ejemplo,' var x; ' crea una variable llamada 'x' con un valor inicial de' undefined', que es distinto de una 'x' inexistente que nunca ha sido declarada). Me decantaría por "no declarado" o "inexistente". –

+0

@ck_: En cuanto a la preservación de los valores existentes, 'var z;' no hace absolutamente nada si 'z' ya existe, cualquiera que sea su valor. –

10

El efecto es correcto. var siempre declarará sus "operandos" de inmediato, mientras que cuando no lo declare, su script intentará usar una variable indefinida y arrojará un error.

Si está en el alcance global, puede asignar una variable inexistente y tendrá el mismo efecto que declararla, mala práctica ya que puede ser. Por supuesto, en tu caso, no está definido.Dicho esto, aunque puede ser por curiosidad intelectual, nunca se le escribir

var z = z || []; 

porque no tiene sentido hacerlo. En su lugar, puede hacer:

if(!window.z) { 
    window.z = []; 
} 

. De hecho, cuando declaro cosas en el ámbito global (que nunca es ;)) utilizo window.something porque hace que mi intento sea más claro.

+0

** cuando no lo declara, su secuencia de comandos intenta usar una variable indefinida ** - espera, ¿está diciendo que z = z accede a z pero var z = z no? La segunda z todavía está en alcance global, como es la primera si está fuera de una función. (desconcertado) –

+1

@ck_: La diferencia es que usar 'var' hace que se cree la variable' z' antes de que se ejecuten las sentencias. –

4

Puede asignar a una variable no declarada z = 123; sin embargo, no puede intentar leer uno que es lo que z = z || [] hace.