¿Hay alguna diferencia entre declarar una variable?
var a=0; //1
...de esta manera:
a=0; //2
...o:
window.a=0; //3
en alcance global?
javascript
Dan
fuente
fuente
Respuestas:
Sí, hay un par de diferencias, aunque en términos prácticos no suelen ser grandes.
Hay una cuarta forma, y a partir de ES2015 (ES6) hay dos más. Agregué la cuarta forma al final, pero inserté las formas ES2015 después del # 1 (verá por qué), por lo que tenemos:
Esas declaraciones explicadas
# 1
var a = 0;
Esto crea una variable global que también es una propiedad del objeto global , al que accedemos como
window
en los navegadores (o mediantethis
un alcance global, en código no estricto). A diferencia de otras propiedades, la propiedad no se puede eliminar mediantedelete
.En términos de especificación, crea un enlace de identificador en el registro de entorno del objeto para el entorno global . Eso lo convierte en una propiedad del objeto global porque el objeto global es donde se guardan los enlaces de identificador para el registro de entorno del objeto del entorno global. Esta es la razón por la cual la propiedad no se puede eliminar: no es solo una propiedad simple, es un enlace de identificador.
El enlace (variable) se define antes de que se ejecute la primera línea de código (consulte "Cuándo
var
sucede" a continuación).Tenga en cuenta que en IE8 y versiones anteriores, la propiedad creada en
window
no es enumerable (no aparece en lasfor..in
declaraciones). En IE9, Chrome, Firefox y Opera, es enumerable.# 1.1
let a = 0;
Esto crea una variable global que no es una propiedad del objeto global. Esto es algo nuevo a partir de ES2015.
En términos de especificación, crea un enlace de identificador en el Registro de entorno declarativo para el entorno global en lugar del registro de entorno del objeto . El medio ambiente mundial es el único que tiene una fracción de Medio Ambiente de registro, uno para todo el material antiguo que va en el objeto global (el objeto de Medio Ambiente Record) y otra para todas las cosas nuevas (
let
,const
y las funciones creadas porclass
) que no lo hacen ir al objeto global.El enlace se crea antes de que se ejecute cualquier código paso a paso en su bloque adjunto (en este caso, antes de que se ejecute cualquier código global), pero no es accesible de ninguna manera hasta que la ejecución paso a paso llegue a la
let
declaración. Una vez que la ejecución alcanza lalet
declaración, la variable es accesible. (Ver "Cuándolet
yconst
suceder" a continuación).# 1.2
const a = 0;
Crea una constante global, que no es una propiedad del objeto global.
const
es exactamente como,let
excepto que debe proporcionar un inicializador (la= value
parte), y no puede cambiar el valor de la constante una vez que se crea. Debajo de las cubiertas, es exactamente iguallet
pero con una bandera en el enlace del identificador que dice que su valor no se puede cambiar. Usarconst
hace tres cosas por ti:# 2
a = 0;
Esto crea una propiedad en el objeto global implícitamente . Como es una propiedad normal, puede eliminarla. Recomiendo no hacer esto, puede no estar claro para cualquiera que lea su código más tarde. Si usa el modo estricto de ES5, hacer esto (asignar a una variable inexistente) es un error. Es una de varias razones para usar el modo estricto.
Y curiosamente, nuevamente en IE8 y versiones anteriores, la propiedad creada no es enumerable (no aparece en las
for..in
declaraciones). Eso es extraño, particularmente dado el n. ° 3 a continuación.# 3
window.a = 0;
Esto crea una propiedad en el objeto global explícitamente, utilizando el
window
global que se refiere al objeto global (en los navegadores; algunos entornos que no son del navegador tienen una variable global equivalente, comoglobal
en NodeJS). Como es una propiedad normal, puede eliminarla.Esta propiedad es enumerable, en IE8 y anteriores, y en cualquier otro navegador que haya probado.
# 4
this.a = 0;
Exactamente como el n. ° 3, excepto que estamos haciendo referencia al objeto global en
this
lugar del globalwindow
. Sin embargo, esto no funcionará en modo estricto, porque en el código global en modo estricto,this
no tiene una referencia al objeto global (en su lugar tiene el valorundefined
).Eliminar propiedades
¿Qué quiero decir con "eliminar" o "eliminar"
a
? Exactamente eso: Eliminar la propiedad (completamente) a través de ladelete
palabra clave:delete
elimina completamente una propiedad de un objeto. No puede hacer eso con las propiedades agregadaswindow
indirectamente a través devar
,delete
se ignora silenciosamente o produce una excepción (dependiendo de la implementación de JavaScript y si está en modo estricto).Advertencia : IE8 nuevamente (y presumiblemente antes, e IE9-IE11 en el modo roto de "compatibilidad"): no le permitirá eliminar las propiedades del
window
objeto, incluso cuando se le debe permitir. Peor aún, arroja una excepción cuando lo intentas ( prueba este experimento en IE8 y en otros navegadores). Entonces, al eliminar delwindow
objeto, debes estar a la defensiva:Eso intenta eliminar la propiedad, y si se lanza una excepción, hace lo mejor y establece la propiedad en
undefined
.Esto solo se aplica al
window
objeto, y solo (hasta donde yo sé) a IE8 y anteriores (o IE9-IE11 en el modo de "compatibilidad" roto). Otros navegadores están bien con la eliminación dewindow
propiedades, sujeto a las reglas anteriores.Cuando
var
sucedeLas variables definidas a través de la
var
declaración se crean antes de ejecutar cualquier código paso a paso en el contexto de ejecución, por lo que la propiedad existe mucho antes de lavar
declaración.Esto puede ser confuso, así que echemos un vistazo:
Ejemplo en vivo:
Mostrar fragmento de código
Como puede ver, el símbolo
foo
se define antes de la primera línea, pero el símbolobar
no. Donde está lavar foo = "f";
declaración, realmente hay dos cosas: definir el símbolo, que ocurre antes de que se ejecute la primera línea de código; y haciendo una asignación a ese símbolo, que sucede donde está la línea en el flujo paso a paso. Esto se conoce como "var
elevación" porque lavar foo
parte se mueve ("eleva") a la parte superior del alcance, pero lafoo = "f"
parte se deja en su ubicación original. (Ver Pobre mal entendidovar
en mi pequeño blog anémico).Cuando
let
yconst
sucederlet
yconst
son diferentes de variasvar
maneras. La forma que es relevante para la pregunta es que, aunque el enlace que definen se crea antes de que se ejecute un código paso a paso, no es accesible hasta que se alcanza la declaraciónlet
oconst
.Entonces, mientras esto se ejecuta:
Esto arroja un error:
Las otras dos formas que difieren
let
y que no son realmente relevantes para la pregunta son:const
var
var
Siempre se aplica a la totalidad del contexto de ejecución (a lo largo código global, o en todo código de función en la función donde aparece), perolet
yconst
aplicación exclusivamente en el bloque en el que aparecen. Es decir,var
tiene la función (o global) alcance, perolet
yconst
tiene ámbito de bloque.Repetir
var a
en el mismo contexto es inofensivo, pero si tienelet a
(oconst a
), tener otrolet a
o aconst a
o avar a
es un error de sintaxis.Aquí hay un ejemplo que demuestra eso
let
yconst
surte efecto inmediatamente en su bloque antes de que se ejecute cualquier código dentro de ese bloque, pero no se puede acceder hasta la instrucciónlet
orconst
:Tenga en cuenta que el segundo
console.log
falla, en lugar de accedera
desde fuera del bloque.Fuera de tema: evite abarrotar el objeto global (
window
)El
window
objeto se vuelve muy, muy abarrotado de propiedades. Siempre que sea posible, recomiendo no agregar nada al desorden. En cambio, envuelva sus símbolos en un pequeño paquete y exporte como máximo un símbolo alwindow
objeto. (Con frecuencia no exporto ningún símbolo alwindow
objeto). Puede usar una función para contener todo su código para contener sus símbolos, y esa función puede ser anónima si desea:En ese ejemplo, definimos una función y la ejecutamos de inmediato (
()
al final).Una función utilizada de esta manera con frecuencia se denomina función de alcance . Las funciones definidas dentro de la función de alcance pueden acceder a las variables definidas en la función de alcance porque son cierres sobre esos datos (ver: Los cierres no son complicados en mi pequeño blog anémico).
fuente
window['a']=0
para dejar en claro que estoy usando la ventana como mapa? ¿Eswindow
especial tal que algunos navegadores no permiten esto y me obligan a usarwindow.a
?window.a = 0;
solo funciona en entornos de navegador y solo por convención. La vinculación del objeto global a una variable denominadawindow
no está en la especificación ES y, por lo tanto, no funcionará, por ejemplo, en V8 o Node.js, mientras quethis.a = 0;
(cuando se invoca en el contexto de ejecución global) funcionará en cualquier entorno ya que la especificación sí especifica que debe haber un objeto global. Si ajusta su código en un IIFE como en la sección Fuera de tema , puede pasarlothis
como un parámetro llamadowindow
oglobal
para obtener una referencia directa al objeto global.var a = 0;
automáticamente se convierte en una propiedad del objeto global. Si declarovar b = 0;
dentro de una declaración de función, ¿será también una propiedad de algún objeto subyacente?Manteniéndolo simple:
El código anterior proporciona una variable de alcance global
Este código dará una variable para ser utilizada en el alcance actual, y debajo de ella
Esto generalmente es lo mismo que la variable global.
fuente
a
bajo el Alcance actual. Usted puede. Además, su uso de "variable global" está un poco fuera de lugar: los dos lugares que dice "variable global" no son más globales que el lugar donde no lo dice.¿Hay algún objeto global del que se cuelguen todos los vars de forma predeterminada? por ejemplo: 'declaración globals.noVar'
fuente
window.*
declaración. Esta declaración parece más segura contra copiar y pegar su código, y también es clara.Basado en la excelente respuesta de TJ Crowder : ( Fuera de tema: Evita el desorden
window
)Este es un ejemplo de su idea:
HTML
init.js (Basado en esta respuesta )
script.js
Aquí está el plnkr . Espero que ayude!
fuente
En el ámbito global no hay diferencia semántica.
Pero realmente debe evitarlo
a=0
ya que establece un valor en una variable no declarada.También use cierres para evitar editar el alcance global
Siempre use cierres y siempre iremos al alcance global cuando sea absolutamente necesario. De todos modos, debe utilizar el manejo de eventos asíncronos para la mayoría de sus comunicaciones.
Como @AvianMoncellor mencionó, hay un error de IE que
var a = foo
solo declara un alcance global para el archivo. Este es un problema con el notorio intérprete roto de IE. Este error suena familiar, por lo que probablemente sea cierto.Así que quédate con
window.globalName = someLocalpointer
fuente
delete
unavar
).var
. Son mecanismos completamente diferentes que tienen el mismo resultado práctico. :-)var
salta al límite de alcance.