47

La siguiente pregunta: ¿Cuando conviene utilizar var, let y const en ECMA Script 6? responde en parte a mi cuestión, pero no del todo.

Leyendo la respuesta aceptada he entendido que:

  • let declara una variable de alcance local

  • const declara una constante dentro de un bloque (¿dentro de una función?)

  • var No llegué a entender si es local o global

  • ¿Y si no se pone nada, cuál es el alcance? En otra pregunta relacionada leí que cuando no se pone nada se está declarando una variable global.

Estoy algo confuso y quisiera entender el alcance exacto de cada forma de declaración de variable, en una respuesta sencilla si es posible.

Por otra parte, no sé si esto sería tema para otra pregunta, pero, no entiendo bien cuál sería el concepto de global en Javascript. ¿La pestaña actual del DOM?, ¿todas las pestañas abiertas?, ¿todos los navegadores y pestañas abiertas?

Rubén
  • 10,857
  • 6
  • 35
  • 79
A. Cedano
  • 86,578
  • 19
  • 122
  • 221
  • 1
    Quizá [este articulo](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#Declarations) en ingles sirva :P – UselesssCat Sep 29 '17 at 15:28
  • 2
    La respuesta de Pablo es excelente. JavaScript no es un lenguaje sencillo, así que no creo que haya una respuesta sencila. Para comprender de verdad la declaración de variables, es importante conocer cómo funcionan los ámbitos en JavaScript. No creo que exista mejor fuente para aprender esto que el repo de GiHub "You-Dont-Know-JS", en concreto la sección "scopes and closures" (https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20&%20closures/README.md#you-dont-know-js-scope--closures). Sé que está en inglés pero no conozco un documento en español que se pueda si quiera comparar. – Roberto Pintos López Sep 05 '18 at 08:01
  • 1
    [Pregunta y respuesta relacionadas](https://es.stackoverflow.com/questions/56116/cuando-conviene-utilizar-var-let-y-const-en-ecma-script-6) (quizá duplicada?) – Pablo Lozano Dec 05 '18 at 08:57

5 Answers5

75

Resumen para los que no quieran leer toda la explicación:

  • const define constantes, pero si no tenemos cuidado se pueden modificar. Tiene alcance de bloque, como let.
  • var define variables con un alcance de función (el contexto actual).
  • let define variables con un alcance de bloque y a partir de la línea en la que se declaran.
  • Si no declaramos un identificador, se creará como una variable global a menos que nuestro código sea declarado "estricto".

const identificador = ...

Crea una constante. Al igual que ocurre en otros lenguajes como Java o C#, si la constante es un objeto sus atributos son modificables, por tanto hay que tener cuidado con lo que hacemos:

function fallaVariableEntera() {
  const k1= 5;
  console.log(k1);
  k1=6;
  console.log(k1);
}
function fallaCreandoObjeto(){
  const k1 = {}
  k1.hola = 'mundo';
  k1 = {}
  console.log(k1);
}
function funciona() {
  const k1={};
  k1.hola='mundo';
  console.log(k1.hola);
}

funciona();
try{
  fallaVariableEntera();
}catch(err){
  console.error(`fallo cambio de valor const =>${err}`)

}
try{
  fallaCreandoObjeto()
}catch(err){
  console.error(`fallo creando un objeto const =>${err}`)

}

var identificador ...

Javascript es un poco especial para según qué cosas y éste es un buen ejemplo de sus rarezas: la variable se puede declarar al usarla, al inicio de nuestro código o al final; realmente dará igual porque el intérprete "subirá" la declaración al inicio del alcance/contexto actual (en inglés a esto se le llama hoisting y también afecta a la declaración de funciones). El alcance es de función siempre, no de bloque:

function ejemplo() {
// la declaro abajo, pero el compilador pondrá la declaración aquí, manteniendo la asignación en el mismo sitio
   a='hola mundo';
   console.log(a);
   var a=6;
   console.log(a);
   
   if (a===6) {
    var b=4; 
   }
   console.log(b); //se declaró en un if, pero su alcance es toda la función
}

ejemplo();

Además, no importa si la declaramos varias veces, las declaraciones extras serán ignoradas:

var a=4

var a=5;

console.log(a)

El comportamiento de los valores de una variable usada con clausuras y callbacks asíncronos suele liar a los programadores inexpertos, pongo un ejemplo y cómo solucionarlo:

function print(c) {
  console.log(c);
}

//generamos una función con un valor fijado de antemano
function generador(c) {
  return function () {
    print(c);
  }
}

for (var i=0;i<5;i++) {
  setTimeout(function () { print(i);});
}

for (var i=0;i<5;i++) {
  setTimeout(generador(i));
}

let identificador = ...

Y llegamos a la última novedad de Javascript, que se comporta de un modo similar a lo que es una declaración de variable en otros lenguajes como Java o C: la variable sólo se puede utilizar a partir de su declaración y su alcance es local al bloque, no a la función:

function funciona() {
  let a='hola';
  console.log(a);
}

function falla() {
  a='hola';
  console.log(a);
  let a;
}

function fallariaTambien() {
  let a=1;
  if (a==1) {
    let b=2;
  }
  console.log(b);
}

funciona();

//se declara una nueva instancia de i para cada iteración!! el problema que teníamos con var desaparece :)
for (let i=0;i<5;i++) {
  setTimeout(()=>console.log(i));
}

try {
  falla();
} catch(e) {
  console.log('Capturado',e.toString());
}
try {
  fallariaTambien();
} catch(e) {
  console.log('Capturado',e.toString());
}

A diferencia de var, no se permiten duplicados:

let a=4;

let a=5;

console.log(a)

¿Y qué pasa si usamos un identificador sin declararlo? Pues tenemos dos escenario: Javascript "normal" y Javascript "estricto"

En el primero la variable se crea como un atributo del objeto global y en el segundo caso hay un error de compilación, avisando de que la variable no ha sido declarada.

function normal() {
  hola='hola';
}

function estricta() {
  'use strict'; 
  // esto indica al intérprete que funcione en modo estricto: todo ha de estar definido o no funcionará
  fallo='esto falla';
}

normal();

console.log(window.hola);

estricta()

Este ejemplo muestra los dos escenarios y, además ayuda a responder a la pregunta "¿Qué es global en Javascript?" Si estamos ejecutando en un navegador, el objeto global es siempre window. Si estamos ejecutando el código en NodeJS, el objeto global es global.

Pero ¡ojo!, window no es toda la ventana del navegador, sino la pestaña actual. Esto es debido a que hasta la llegada de Firefox no había pestañas y cada página que abríamos en un navegador obligaba a tener una ventana nueva abierta. Por seguridad no podemos compartir variables entre diferentes pestañas.

Pablo Lozano
  • 45,934
  • 7
  • 48
  • 87
  • 7
    Le doy mi +1 a esta respuesta pues aparte de estar muy completa, veo difícil que alguien mas pueda hacer un aporte con contenido que no este ya redactado aquí. – BetaM Aug 29 '19 at 16:03
  • Excelente respuesta, quede un poco perdido en la parte de donde usas el `setTimeout` , pero claro, muy buena la respuesta con ejemplos reproducibles – Pedro Miguel Pimienta Morales Jan 09 '20 at 14:16
13

var declará una variable local, es decir si declaras

function miVar() {
  var x = 0;
}

x solo tendrá alcance dentro de la función miVar, si declararás al inicio de todo el js var x = 0; fuera de cualquier función esta tendrá alcance en todo el js.

Si no pones var declaras una variable global, ahora cual es la diferencia entre declarar una variable global y una variable local pero en todo el js? Que si tu pones var x = 0; al inicio del js este solo tendrá alcance en el js actual, si la declaras global tendrá alcance en todo los js que estén declarados en el html. Es decir si en un js declaro x = 0; puedo usar en otro js la variable x y tendrá el valor de 0

Const podría ser como una variable global al igual que x = 0, pero la gran diferencia es que al ser constante no puede ser redeclarada, es decir si tu pones const x = 0; no puedes después en una función poner x = 2.

Como esta página lo explica al respecto en const, se puede cambiar en casos de array, es decir irla llenando o quitando elementos https://mathiasbynens.be/notes/es6-const

Let sirve para declarar variables un poco más locales, como esta respuesta lo explica https://stackoverflow.com/questions/762011/whats-the-difference-between-using-let-and-var-to-declare-a-variable

prácticamente var toma el block padre por así decirlo, si usas un let en un for dentro de una función

function varExp(){
  for( let i = 0; i < 5; i++ ) {

    }
}

let solo estará disponible dentro del for, si lo haces con un var, estará en toda la función

Sr1871
  • 4,737
  • 1
  • 8
  • 16
4

En los inicios de JavaScript var era la única forma en la que se podía crear una variable. Mucho despúes let y const nacen con el estándar de EcmaScript 6.

Características de var

Se puede reinicializar.

var name = 'Andy'
var name = 'AndyGeek'

Se puede reasignar.

var name = 'Andy'
    name = 'AndyGeek'
console.log(name)   // AndyGeek

Su alcance es global.

if(true){
    var name = 'andy'
}
else{
    name = 'andygeek'
}
console.log(name)

Esto también nos permitiría crear variables var con el mismo nombre dentro de varios if u otra estructura anidada. Incluso por su alcance nos si ejecutamos el siguiente código no obtendríamos errores.

console.log('My name is ' + name)
var name = 'Andy'
// My name is undefined

Esto no es nada intuitivo, lo que nos podría traer problemas a la hora de programar. Así que, el consejo es no usar var.

Características de let

No se puede reinicializar.

let name = 'Andy'
let name = 'AndyGeek'
// Mostrará un error

Se puede reasignar.

let name = 'Andy'
    name = 'AndyGeek'
console.log(name)   // AndyGeek

Su alcance es de bloque.

if(true){
    let name = 'andy'
}
else{
    name = 'andygeek'
    // El compilador no reconoce name
}
console.log(name)

Características de const

No se puede reinicializar.

const name = 'Andy'
const name = 'Andygeek'
// Obtendremos error al ejecutarlo

No se puede reasignar. Al ser una constante esta es su principal característica. No podemos cambiar el elemento completo de nuestra constante.

const name = 'Andy'
      name = 'AndyGeek'
// Obtendremos error al ejecutarlo

No es inmutable. Podemos cambiar las propiedades del elemento constante, pero no todo el elemento. Esto lo explicaremos mediante un objeto.

const people = {
name: 'Andy'
}
console.log(people.name)    // Andy
people.name = 'AndyGeek'
console.log(people.name)    // AndyGeek
Candid Moe
  • 21,247
  • 9
  • 18
  • 40
AndyGeek
  • 61
  • 4
1

Para el uso de operaciones en funciones.

Las const las debes usar dentro de las funciones si son valores de solo sirven de referencia, si este valor no va a cambiar en las función y los let los utilizas cuando necesitas cambiar un valor. Tanto las const, como los let se utilizan mucho en funciones, ya sea por legibilidad del código o el uso de una variable contadora o acumuladora.

function myFunction() {
    const list = [0,10,2,3,5,7,14,2,7];//Referencia
    let count = 0;//contadora

    for (var i = list.length - 1; i >= 0; i--) {
        if (list[i] % 2 != 0){
            count++;
        }
    }

    return count;
}

Para exports

Normalmente cuando se un import de un namespace (archivo, librería, ect), se requiere exponer ciertas funciones, variables o constantes y estas no van a cambiar en la aplicación por lo tanto serian const.

//normalmente en el un archivo de constants.js
export const MAIN_COLOR = #ff0000;
//normalmente en el archivo de helpers.js o utils.js
export const deepCopy = (obj) => JSON.parse(JSON.stringify(obj));

nota: no se te olvide que para const de referencia poner en mayusculas, ya que son valores que sirven para toda aplicación.

Cosas para que tengas en cuenta

  • Si utilizas javascript a secas, tienes que hacer uso de var, ya que en los navegadores viejos no pueden tomar const y let.
  • Las variables o constantes globales son las que se pueden acceder desde cualquier parte.

Esta respuesta es un ejemplo mas practico de uso de let y const en javascript.

  • Disculpa, la respuesta parece una traducción de algún articulo en ingles, por ejemplo en la parte "Normalmente cuando **hacer** un import de un namespace (archivo, librería, ect), se requiere exponer...", si es así procura proporcionar las fuentes de la información y que el texto este bien redactado, saludos. – the-breaker Aug 28 '19 at 23:48
  • Mala mía, se me paso por no revisar bien lo que escribí y el ejemplo de lo de namespace es por lo que vengo del palo de programar en C#. (igualmente gracias por avisarme de estos errores) – Steven Aragón Urrea Aug 28 '19 at 23:59
  • tu pregunta me da recomendacion pero no me dice cuando usarlo – JackNavaRow Aug 29 '19 at 13:35
0

Resumen para los que no quieran leer toda la explicación:

  • const define constantes, pero si no tenemos cuidado se pueden modificar. Tiene alcance de bloque, como let.

  • var define variables con un alcance de función (el contexto actual).

  • let define variables con un alcance de bloque y a partir de la línea en la que se declaran.

  • Si no declaramos un identificador, se creará como una variable global a menos que nuestro código sea declarado "estricto".

2coolDevs
  • 336
  • 11
  • ¿Por qué tu respuesta es una copia (casi) fiel de la primera parte de [esta respuesta](https://es.stackoverflow.com/a/106067)? – padaleiana Mar 18 '22 at 18:43