ES6: Scope en JavaScript | var, let y const
Tags: javascript, spanish, webdev, es6
Published: 2020-07-06 14:41:48


## **El Scope de las variables en JavaScript**
Antes de empezar a analizar las nuevas maneras de declarar variables (`let` y `const`) es menester comprender el ámbito de las mismas en JavaScript.
El scope de una variable se define como el alcance que tiene esta dentro del código, es decir, en que puntos del programa una variable puede ser usada y en qué puntos no.

## **Tipos de variables**
1. **Variables Locales:** una variable local es aquella que está declarada dentro de un bloque de código, por lo general dentro de una función (aunque puede estar declarada también dentro de un condicional o una estructura repetitiva), se caracteriza por que se declara usando la palabra reservada `var` o `let`.
2. **Variables Globales:** una variable global es toda aquella que está definida fuera de todo bloque de código.

> *Un bloque de código es aquel que está delimitado por llaves.*

## **Scope local**
Consideremos el siguiente ejemplo sencillo: 

```javascript
function saludar(){
  var nombre ="Gabriela";
  console.log("Hola " + nombre);
}

console.log(nombre);
```
La línea de código `var nombre ="Gabriela";` declara una variable local de tipo string, por ende cuando intentamos acceder a la variable `nombre` fuera del bloque de código donde fue definida (en este caso fuera de la función) obtenemos un error: `Uncaught ReferenceError: nombre is not defined`, esto en otras palabras significa que para el intérprete de JavaScript `nombre` solo existe dentro de la función y por ende solo puede ser usada en la función.
Si llamamos a la función:

```javascript
function saludar(){
  var nombre ="Gabriela";
  console.log("Hola " + nombre);
}

saludar()
```
Obtenemos la salida esperada por consola: `Hola Gabriela` porque el `console.log()` usa la variable `nombre` dentro de la función.

## **Scope Global**
Supongamos que tenemos el siguiente código:

```javascript
var consejo = "Quedate en casa! Cuida a los tuyos";

function mensaje(){
  console.log(consejo);
}

mensaje();
```
¿Qué imprimirá la consola? 
La variable `consejo` está declarada fuera de todo bloque de código, entonces `consejo` es global, una variable global puede ser accedida dentro de un bloque sin ningún inconveniente. 

## **¿Qué sucede si declaramos una variable sin var, let o const?**

Si declaramos una variable dentro o fuera de un bloque de código sin usar ninguna palabra reservada, esta automáticamente se trasforma en una variable global.

```javascript

function saludar(){
  nombre ="Gabriela";
}
saludar()
console.log(nombre);

```
Refactorizando el primer ejemplo de este post bajo esta lógica, imprimiríamos por consola Gabriela.

## **Casos interesantes con el Scope** 
### **Variable Local vs Variable Global**
¿Qué ocurriría si tenemos una variable local y otra global con el mismo nombre? Considera el siguiente ejemplo:

```javascript

var mensaje = "gana global";

function imprimirMensaje(){
  var mensaje = "gana local";
  console.log(mensaje)
}

console.log(mensaje);
imprimirMensaje();
console.log(mensaje);

/* salida:
"gana global"
"gana local"
"gana global"
*/
```
En este caso las variables locales prevalecen dentro de su respectivo bloque.

### **Variable Global vs Variable Global**
Imaginemos que tenemos 2 variables globales que comparten el mismo nombre:

```javascript
var mensaje = "gana global";

function imprimirMensaje(){
  mensaje = "gana local";
  console.log(mensaje)
}

console.log(mensaje);
imprimirMensaje();
console.log(mensaje);

/* salida
"gana global"
"gana local"
"gana local"
*/
```
En este caso se respeta el flujo del programa, al llamar a la función `imprimirMensaje();` la variable mensaje se 'setea' con el valor "gana local" y al querer imprimir la variable `mensaje` nuevamente muestra por consola "gana local" por qué su valor se sobre escribió.

Después de esa extensa introducción de repaso sobre cómo funciona el ámbito de las variables es momento de hacer hincapié en las nuevas características de ES6 para la definición de variables

## **¿Qué es let?** 🤨
`let` es una nueva forma de declarar variables, permite al programador proteger el valor de una variable dentro del bloque donde se la asigna.

## **Diferencias entre var y let**

```javascript
var edad = 25;

if(edad >= 18){
  var mensaje = "Es adulto"
}

console.log(mensaje);
//salida:
//"Es adulto"
```

Declaramos una variable `edad` con `var` y luego verificamos que `edad` sea mayor a 18, de ser así imprimimos `Es adulto` **FUERA DEL BLOQUE IF.** Este es un código perfectamente válido, pero que pasa si hacemos lo mismo pero con `let`:

```javascript
let edad = 25;

if(edad >= 18){
  let mensaje = "Es adulto"
}

console.log(mensaje);
//salida:
//Uncaught ReferenceError: mensaje is not defined
```

¿Qué sucedió acá? 😒
![wft](https://media.giphy.com/media/xL7PDV9frcudO/giphy.gif)

¿Aparentemente hicimos lo mismo no? Solo cambiamos `let` por `var`. Aqui radica la principal diferencia entre ambas palabras reservadas y la explicación es bastante sencilla, aunque no lo creas; como habíamos mencionado `let` encapsula a la variable dentro de un bloque (en este caso un if) por ende, al pretender usar la variable fuera de ese bloque salta el error `mensaje is not defined`, esto obliga al programador a usar las variables dentro del mismo bloque donde se las declara evitando así que las mismas se sobre escriban en un futuro.

Corrigiendo el último fragmento de código, se vería de la siguiente manera: 

```javascript
let edad = 25;

if(edad >= 18){
  let mensaje = "Es adulto"
  console.log(mensaje);
}
//salida:
//"Es adulto"

```
> *Si tratamos de imprimir la variable `mensaje` dentro del mismo bloque no pasa ningún problema*

Otra diferencia importante entre `var` y `let` es la reasignación de valores, con esto me refiero a lo siguiente:

```javascript
var color = "Rojo";
var color = "Violeta";

console.log(color);
//salida: Violeta
```
Este código es perfectamente válido, pero puede producir varios errores a futuro, ¿¡porque si tengo una variable `color = "Rojo"` quisiera después reasignar su valor a `color = "Violeta"`!? ¿Carece totalmente de todo sentido común, por ello ES6 con `let` corrige este pequeño problema:

```javascript
let color = "Rojo";
let color = "Violeta";

console.log(color);
//salida: Uncaught SyntaxError: redeclaration of let color
```
> * `let` protege al programador de reescribir valores de variables evitando errores lógicos futuros*

## **¿Qué es const?**
`const` permite declarar constantes, ósea, espacios en memoria que son inmutables en el tiempo. 

```javascript
const PI = Math.PI;

console.log(PI)

//salida: 3.141592653589793

```
> *Por convenciones se acostumbra declarar las constantes con mayúsculas*

Una constante al ser inmutable no permite que su valor se altere una vez declarada, el siguiente ejemplo devolvería un error:

```javascript
const fruta = "Manzana";

let fruta = "Zandia";

console.log(fruta);

//salida: Uncaught SyntaxError: redeclaration of const fruta
```
Esta peculiaridad se da con cadenas de texto, boleanos y valores numéricos, pero con un arreglo se pierde la inmutabilidad.

```javascript
const nombres =["Carlos","Ramiro"];

nombres.unshift("Ana");

console.log(nombres);

//salida: ["Ana", "Carlos", "Ramiro"]
```
> *Al intentar alterar un arreglo declarado con `const` se pierde la inmutabilidad.*

Algo similar sucede con los objetos:

```javascript
const persona = [
{id:1, "nombre":"Carlos","edad":19}
];

persona.push({id:2, "nombre": "Ruben", "edad":20});

console.log(persona);
/*salida:
[[object Object] {
  edad: 19,
  id: 1,
  nombre: "Carlos"
}, [object Object] {
  edad: 20,
  id: 2,
  nombre: "Ruben"
}]*/
```
Con esto concluye este post, si tienes alguna pregunta con gusto la respondo en la caja de comentarios.

## **Referencias** ✅
* https://www.jesusda.com/docs/ebooks/introduccion_javascript.pdf
* https://www.youtube.com/watch?v=oqrDD70roLQ 

---

## **Conclusiones**💻
* Comprender y dominar el scope de Javascript es vital para evitar errores lógicos en nuestros desarrollos.
* Las variables locales deben ser declaradas con las palabras reservadas `var`, `let` o `const`, de lo contrario el intérprete de JavaScript las convierte automáticamente en un variable global.
* El scope global no puede acceder al scope local, esto produce un error de variable indefinida. 
* El scope local si puede acceder al scope global sin ningún inconveniente. 
* Si una variable local y otra global comparten el mismo nombre, las variables locales prevalecen dentro de su respectivo bloque.
* Si dos variables globales comparten el mismo nombre estas se sobre escriben. 
* `let` encapsula una variable dentro de un bloque, porque no no podrá ser usada fuera del mismo.
* `let` evita reescribir el valor de una variable, cosa que `var` no hace.
* `var` y `let` comparten el mismo scope.
* Las constantes inmutables con cadenas de texto, strings, boleanos, enteros y flotantes.
* Las constantes pierden su inmutabilidad con arreglos y objetos.
* Usa `let` o `const` cada vez que te sea posible, `var` es una forma anticuada de declarar variables y debería dejar de usarse.