Este artículo es para comprender scripts antiguos.
La información de este artículo es útil para comprender scripts antiguos.
No es así como escribimos código nuevo.
En el primer capítulo sobre variables, mencionamos tres formas de declaración de variables:
let
const
var
La declaración var
es similar a let
. La mayoría de las veces podemos reemplazar let
por var
o viceversa y esperar que todo funcione:
var mensaje = "Hola"; alerta(mensaje); // Hola
Pero internamente var
es una bestia muy diferente, que tiene su origen en tiempos muy antiguos. Generalmente no se utiliza en las escrituras modernas, pero aún se esconde en las antiguas.
Si no planea cumplir con dichos guiones, puede incluso saltarse este capítulo o posponerlo.
Por otro lado, es importante comprender las diferencias al migrar scripts antiguos de var
a let
para evitar errores extraños.
Las variables, declaradas con var
, tienen un ámbito de función o un ámbito global. Son visibles a través de bloques.
Por ejemplo:
si (verdadero) { prueba var = verdadero; // usa "var" en lugar de "let" } alerta(prueba); // verdadero, la variable vive después de si
Como var
ignora los bloques de código, tenemos una test
de variable global.
Si usáramos let test
en lugar de var test
, entonces la variable solo sería visible dentro if
:
si (verdadero) { dejar prueba = verdadero; // usa "dejar" } alerta(prueba); // ReferenceError: la prueba no está definida
Lo mismo para los bucles: var
no puede ser local en bloque o en bucle:
para (var i = 0; i < 10; i++) { var uno = 1; //... } alerta(i); // 10, "i" es visible después del ciclo, es una variable global alerta(uno); // 1, "uno" es visible después del ciclo, es una variable global
Si un bloque de código está dentro de una función, entonces var
se convierte en una variable de nivel de función:
función decir Hola() { si (verdadero) { var frase = "Hola"; } alerta(frase); // obras } decir Hola(); alerta(frase); // ReferenceError: la frase no está definida
Como podemos ver, var
atraviesa if
, for
u otros bloques de código. Esto se debe a que hace mucho tiempo en JavaScript, los bloques no tenían entornos léxicos y var
es un remanente de eso.
Si declaramos la misma variable con let
dos veces en el mismo alcance, eso es un error:
dejar usuario; dejar usuario; // SyntaxError: 'usuario' ya ha sido declarado
Con var
, podemos redeclarar una variable cualquier cantidad de veces. Si usamos var
con una variable ya declarada, simplemente se ignora:
var usuario = "Pete"; var usuario = "Juan"; // esta "var" no hace nada (ya declarada) // ...no genera un error alerta(usuario); // John
Las declaraciones var
se procesan cuando se inicia la función (o se inicia el script para globales).
En otras palabras, las variables var
se definen desde el principio de la función, sin importar dónde esté la definición (suponiendo que la definición no esté en la función anidada).
Entonces este código:
función decir Hola() { frase = "Hola"; alerta(frase); frase var; } decir Hola();
…Es técnicamente lo mismo que esto ( var phrase
movida arriba):
función decir Hola() { frase var; frase = "Hola"; alerta(frase); } decir Hola();
…O incluso así (recuerde, los bloques de código se ignoran):
función decir Hola() { frase = "Hola"; // (*) si (falso) { frase var; } alerta(frase); } decir Hola();
La gente también llama a este comportamiento "elevar" (elevar), porque todas var
son "elevadas" (elevadas) a la parte superior de la función.
Entonces, en el ejemplo anterior, la rama if (false)
nunca se ejecuta, pero eso no importa. La var
dentro se procesa al comienzo de la función, por lo que en el momento de (*)
la variable existe.
Se alzan declaraciones, pero no cesiones.
Eso se demuestra mejor con un ejemplo:
función decir Hola() { alerta(frase); var frase = "Hola"; } decir Hola();
La línea var phrase = "Hello"
tiene dos acciones:
var
declaración de variables
Asignación de variables =
.
La declaración se procesa al inicio de la ejecución de la función (“izada”), pero la asignación siempre funciona en el lugar donde aparece. Entonces el código funciona esencialmente así:
función decir Hola() { frase var; // la declaración funciona al principio... alerta(frase); // indefinido frase = "Hola"; // ...asignación - cuando la ejecución la alcanza. } decir Hola();
Debido a que todas las declaraciones var
se procesan al inicio de la función, podemos hacer referencia a ellas en cualquier lugar. Pero las variables no están definidas hasta las asignaciones.
En los dos ejemplos anteriores, alert
se ejecuta sin error porque la phrase
variable existe. Pero su valor aún no está asignado, por lo que se muestra undefined
.
En el pasado, como solo existía var
y no tenía visibilidad a nivel de bloque, los programadores inventaron una forma de emularlo. Lo que hicieron se denominó “expresiones de función invocadas inmediatamente” (abreviadas como IIFE).
Eso no es algo que debamos usar hoy en día, pero puedes encontrarlos en scripts antiguos.
Un IIFE se ve así:
(función() { var mensaje = "Hola"; alerta(mensaje); // Hola })();
Aquí, se crea una expresión de función y se llama inmediatamente. Entonces el código se ejecuta de inmediato y tiene sus propias variables privadas.
La expresión de función está entre paréntesis (function {...})
, porque cuando el motor JavaScript encuentra "function"
en el código principal, la entiende como el comienzo de una declaración de función. Pero una Declaración de Función debe tener un nombre, por lo que este tipo de código dará un error:
// Intenta declarar y llamar inmediatamente a una función function() { // <-- SyntaxError: las declaraciones de función requieren un nombre de función var mensaje = "Hola"; alerta(mensaje); // Hola }();
Incluso si decimos: "está bien, agreguemos un nombre", eso no funcionará, ya que JavaScript no permite que se llamen declaraciones de funciones inmediatamente:
// error de sintaxis debido a los paréntesis a continuación función ir() { }(); // <-- no se puede llamar a la Declaración de Función inmediatamente
Entonces, el paréntesis alrededor de la función es un truco para mostrarle a JavaScript que la función se crea en el contexto de otra expresión y, por lo tanto, es una expresión de función: no necesita nombre y se puede llamar inmediatamente.
Existen otras formas además de los paréntesis para indicarle a JavaScript que nos referimos a una expresión de función:
// Formas de crear IIFE (función() { alert("Paréntesis alrededor de la función"); })(); (función() { alert("Paréntesis alrededor de todo"); }()); !función() { alert("El operador NOT bit a bit inicia la expresión"); }(); +función() { alert("Unario más inicia la expresión"); }();
En todos los casos anteriores declaramos una expresión de función y la ejecutamos inmediatamente. Notemos nuevamente: hoy en día no hay razón para escribir dicho código.
Hay dos diferencias principales entre var
y let/const
:
Las variables var
no tienen alcance de bloque, su visibilidad tiene como alcance la función actual, o global, si se declara fuera de la función.
Las declaraciones var
se procesan al inicio de la función (inicio del script para globales).
Hay una diferencia más, muy pequeña, relacionada con el objeto global, que cubriremos en el próximo capítulo.
Estas diferencias hacen que var
sea peor que let
la mayor parte del tiempo. Las variables a nivel de bloque son algo grandioso. Es por eso let
se introdujo en el estándar hace mucho tiempo y ahora es una forma importante (junto con const
) de declarar una variable.