declaraciones de variables (y declaraciones de funciones) son izada a la parte superior del alcance en el que aparecen. Las asignaciones suceden en el lugar. El código es interpretado de manera efectiva como esto:
var a;
var a;
a = 'string1';
Por ejemplo, consideremos lo que ocurre si se declara una variable dentro de un cuerpo if
declaración:
console.log(myVar); //undefined (NOT a reference error)
if (something === somethingElse) {
var myVar = 10;
}
console.log(myVar); //10
Debido a que JavaScript no tiene ámbito de bloque, todas las declaraciones en cada alcance se eleva a la parte superior de ese alcance. Si intentas registrar alguna variable que no fue declarada, obtendrías un error de referencia. El ejemplo anterior se interpreta así:
var myVar; //Declaration is hoisted
console.log(myVar);
if (something === somethingElse) {
myVar = 10; //Assignment still happens here
}
console.log(myVar);
Así que incluso si la condición se evalúa false
, la variable myVar
sigue siendo accesible. Esta es la razón principal por la que JSLint le dirá que mueva todas las declaraciones a la parte superior del alcance en el que aparecen.
En poco más de detalle ... esto es lo que el ECMAScript 5 spec tiene que decir (en negrita cursiva es nuestra):
Para cada VariableDeclaration y VariableDeclarationNoIn d en código, en orden de texto fuente do
- Deje dn sea el Identificador en d.
- Vamos varAlreadyDeclared ser el resultado de llamar concreto HasBinding método de env pasar dn como argumento.
- Si varAlreadyDeclared es
false
, entonces
- llamada de env CreateMutableBinding método concreto que pasa dn y configurableBindings como los argumentos.
- llamada método concreto SetMutableBinding de env pasar dn,
undefined
, y estricta como los argumentos.
Por lo tanto, si una unión ya existe con el identificador que estamos tratando de unir ahora, no pasa nada.
+1, pregunta interesante. –
Las variables locales también deberían exhibir este mismo comportamiento. – hugomg