¿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
windowen los navegadores (o mediantethisun 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
varsucede" a continuación).Tenga en cuenta que en IE8 y versiones anteriores, la propiedad creada en
windowno es enumerable (no aparece en lasfor..indeclaraciones). 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,consty 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
letdeclaración. Una vez que la ejecución alcanza laletdeclaración, la variable es accesible. (Ver "Cuándoletyconstsuceder" a continuación).# 1.2
const a = 0;Crea una constante global, que no es una propiedad del objeto global.
constes exactamente como,letexcepto que debe proporcionar un inicializador (la= valueparte), y no puede cambiar el valor de la constante una vez que se crea. Debajo de las cubiertas, es exactamente igualletpero con una bandera en el enlace del identificador que dice que su valor no se puede cambiar. Usarconsthace 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..indeclaraciones). 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
windowglobal que se refiere al objeto global (en los navegadores; algunos entornos que no son del navegador tienen una variable global equivalente, comoglobalen 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
thislugar del globalwindow. Sin embargo, esto no funcionará en modo estricto, porque en el código global en modo estricto,thisno 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 ladeletepalabra clave:deleteelimina completamente una propiedad de un objeto. No puede hacer eso con las propiedades agregadaswindowindirectamente a través devar,deletese 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
windowobjeto, 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 delwindowobjeto, 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
windowobjeto, 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 dewindowpropiedades, sujeto a las reglas anteriores.Cuando
varsucedeLas variables definidas a través de la
vardeclaració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 lavardeclaración.Esto puede ser confuso, así que echemos un vistazo:
Ejemplo en vivo:
Mostrar fragmento de código
Como puede ver, el símbolo
foose define antes de la primera línea, pero el símbolobarno. 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 "varelevación" porque lavar fooparte se mueve ("eleva") a la parte superior del alcance, pero lafoo = "f"parte se deja en su ubicación original. (Ver Pobre mal entendidovaren mi pequeño blog anémico).Cuando
letyconstsucederletyconstson diferentes de variasvarmaneras. 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ónletoconst.Entonces, mientras esto se ejecuta:
Esto arroja un error:
Las otras dos formas que difieren
lety que no son realmente relevantes para la pregunta son:constvarvarSiempre 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), peroletyconstaplicación exclusivamente en el bloque en el que aparecen. Es decir,vartiene la función (o global) alcance, peroletyconsttiene ámbito de bloque.Repetir
var aen el mismo contexto es inofensivo, pero si tienelet a(oconst a), tener otrolet ao aconst ao avar aes un error de sintaxis.Aquí hay un ejemplo que demuestra eso
letyconstsurte 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ónletorconst:Tenga en cuenta que el segundo
console.logfalla, en lugar de accederadesde fuera del bloque.Fuera de tema: evite abarrotar el objeto global (
window)El
windowobjeto 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 alwindowobjeto. (Con frecuencia no exporto ningún símbolo alwindowobjeto). 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']=0para dejar en claro que estoy usando la ventana como mapa? ¿Eswindowespecial 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 denominadawindowno 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 pasarlothiscomo un parámetro llamadowindowoglobalpara 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
abajo 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=0ya 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 = foosolo 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 = someLocalpointerfuente
deleteunavar).var. Son mecanismos completamente diferentes que tienen el mismo resultado práctico. :-)varsalta al límite de alcance.