Herramientas de usuario

Herramientas del sitio


informatica:programacion:cursos:programacion_avanzada_javascript:declaracion_variables_let_const

¡Esta es una revisión vieja del documento!


Declaración de variables con let y const

Módulo perteneciente al curso Programación avanzada con JavaScript y ECMAScript.

ECMAScript

La sintaxis y capacidades del lenguaje JavaScript se encuentran reguladas por el organismo ECMA (European Computer Manufacturer Association - Asociación Europea de Fabricantes de Computadoras). Se trata de una organización sin ánimo de lucro que se encarga, entre otras cosas, de regular el funcionamiento de muchos estándares de la industria mundial, no solo de Europa. Entre estos estándares se encuentran los de algunos lenguajes de programación, como por ejemplo C# (que es el estándar ECMA-334), las extensiones del lenguaje C++/CLI, el lenguaje de descripción de servicios Web (WSDL) o, por supuesto, nuestro queridísimo ECMAScript que es el estándar ECMA-262.

JavaScript es una de las implementaciones del estándar ECMA-262, en concreto la que se usa en los navegadores. Pero existen otras implementaciones con sus propias extensiones, como por ejemplo ActionScript, el lenguaje que se usaba para programar Flash que se lanzó también en 1997.

La primera versión de JavaScript, ECMAScript 1, se lanzó en Junio de 1997, y desde entonces han existido las versiones 2, 3 y 5 (la 4 se abandonó), que es la que se conoce generalmente como simplemente JavaScript. Durante varios años ECMA estuvo trabajando en la siguiente versión del lenguaje, conocida como ECMAScript 6, y en junio de 2015 por fin vio la luz la versión definitiva, con el nombre oficial ECMAScript 2015.

Se trata de una evolución del lenguaje JavaScript para dotarlo de características avanzadas que se echaban mucho en falta y que sí estaban disponibles en otros lenguajes populares, como por ejemplo:

  • Mejoras de sintaxis: parámetros por defecto, let, plantillas…
  • Módulos para organización de código
  • Sintaxis de “verdaderas” clases para programación orientada a objetos
  • Promesas, para programación asíncrona
  • Mejoras en programación funcional: expresiones de flecha, iteradores, generadores…

En Junio de 2016 ECMA lanzó una nueva versión del lenguaje, ECMAScript 2016 también conocida por algunos como ECMAScript 7, pero no es el ES7 que te piensas. En esta revisión sin embargo las novedades son mínimas, pero alguna hay.

Posteriormente, cada año se han ido introduciendo novedades en el lenguaje. En este completo segundo bloque se estudian a fondo todas y cada una de las novedades relevantes que han ido introduciendo las sucesivas versiones de ECMAScript, hasta la más reciente, y cómo aplicarlas tanto en navegadores que las soportan de manera nativa, como en navegadores más antiguos mediante el uso de transpiladores.

Entre otras cosas aprenderás:

  • Nuevas funciones y tipos de datos
  • Nuevas formas de declarar variables y su efecto en el ámbito, this, etc…
  • Nuevos tipos de colecciones y agrupamientos de información
  • Promesas
  • Operador flecha, pérdida de this, uso de lambdas
  • Mejoras y cambios en definición y notación de objetos
  • Uso de literales de cadena y plantillas
  • Símbolos y sus aplicaciones avanzadas
  • Weakmaps
  • Fetch
  • Async/await
  • Desestructuración de datos y el operador “spread”
  • Nuevos tipos de bucles
  • Iteradores y generadores
  • Programación orientada a objetos con ECMAScript
  • Creación y uso de proxies.
  • Modularización de código
  • Transpilación a ES5

¡Adelante!

Hoisting

El hoisting es una característica que muchos desarrolladores que han estado usando el lenguaje desconocen. Consiste en que, con independencia de donde declaremos una variable, la declaración se mueve al principio del ámbito. Además debemos tener presente que JavaScript tiene tan solo dos ámbitos: ámbito global o ámbito local (de función). No existe, como en otros lenguajes, el ámbito de bloque (aunque esto último cambia, como vamos a ver en este módulo).

Ámbito: Región de código en la cual una variable es accesible a través de su identificador. Decimos que una variable “sale de ámbito” cuando deja de ser accesible. JavaScript ha tenido siempre dos ámbitos: local y global. EcmaScript 2015 añade el ámbito de bloque.

¿Qué crees que imprime el siguiente código?

'use strict';
var n = 'eiximenis';
function foo() {
    n = 'campusMVP';
    var n = null;
    for (var i=0; i<10; i++) {
        n = 'iter ' + i;
    }
}
foo();
console.log(n);

Este código no da error. Se puede observar el uso del modo estricto, para que el motor de JavaScript nos avise de que accedemos a cualquier variable no declarada previamente. Se puede ver que la primera línea de la función foo accede a una variable n. Lo normal es pensar que esta variable n a la que se accede es la variable global cuyo valor es eiximenis. Posteriormente, se declara una variable local con el mismo nombre n. Sabemos que las variables locales “ocultan” a las globales si tienen el mismo nombre. Por lo tanto las asignaciones dentro del for afectan a la variable local, no a la global.

Visto así, lo lógico es pensar que al final de este código la variable local valdrá “iter 9” y la variable global tendrá el valor de “campusMVP”. Pero eso no es así. Al finalizar este código la variable global sigue teniendo el valor de “eiximenis. ¿Cómo se entiende eso? Pues por el hoisting.

Recuerda que el hoisting significa que todas las declaraciones de variables se mueven al principio del ámbito correspondiente (y recuerda que aparte del global, el único ámbito existente es el local). Así, el código anterior es como si realmente se hubiese escrito:

'use strict';
var n = 'eiximenis';
function foo() {
    var n;              // La declaración se mueve al principio de la función
    n = 'campusMVP';
    n = null;
 
    for (var i=0; i<10; i++) {
        n = 'iter ' + i;
    }
}
foo();
console.log(n);

Leyendo este código queda claro que la asignación del valor ”campusMVP” es a la variable local, no a la global, y por lo tanto, se puede ver claramente que el valor de la variable global nunca se modifica dentro de la función foo. Como se puede comprobar en el ejemplo anterior, el uso del modo estricto no te previene de los efectos del hoisting.

Otra forma de definir el hoisting consiste en decir que dentro de un ámbito concreto (local, global, bloque) un identificador en concreto (es decir un nombre de variable) siempre hace referencia a la misma variable (por eso en el ejemplo, dentro del ámbito local el identificador “n” siempre hace referencia a la misma variable: la variable local “n”, aunque ésta esté definida posteriormente al código que accede a ella). En lenguajes que no tienen hoisting un mismo nombre de variable puede referenciar a variables distintas en función de cuando se use este nombre. Todas las declaraciones en JavaScript tienen hoisting, incluidas las variables declaradas con las nuevas palabras clave “let” y “const”, a pesar de que en algunos sitios puedas leer lo contrario. En la lección siguiente se amplía esta información.

Declaración de variables con let

En ES2015 se introduce una nueva palabra clave, let, que se puede usar para declarar variables. A todos los efectos let es como var pero con dos diferencias importantes:

  Las variables declaradas con let no se ven afectadas por el hoisting. Realmente, eso no es del todo cierto (más detalles a continuación) aunque lo verás escrito en muchos sitios porque los efectos finales son muy parecidos.
  Las variables declaradas con let tienen ámbito de bloque.
  Una nota (un pelín técnica) sobre el tema del hoisting y let. Realmente a todas las declaraciones en JavaScript (var, let, const, function, class) se les aplica el hoisting. La sutileza está en que las variables definidas por let (y const, como veremos) al declararse están en un estado, conocido como dead zone, en el cual su valor no vale undefined, sino que es un error de referencia. Es decir, acceder a una variable que está en dead zone da un error de referencia. Una variable solo puede salir de este estado cuando se le asigna un valor. Es por esto, que técnicamente, decimos que no hay hoisting porque el comportamiento es casi equivalente. Y en el "casi" está la clave: una variable declarada con let ocultará a una variable de ámbito superior del mismo nombre, incluso antes de ser declarada (dentro de su ámbito correspondiente), aunque acceder a ella produzca un error si este acceso ocurre antes de su declaración. Eso sí, es importante saber que el hoisting se aplica según el ámbito de visibilidad: es decir, una variable declarada con let tiene hoisting al inicio de su bloque, mientras que una variable declarada con var tiene hoisting siempre al inicio de la función (dado que var no tiene visibilidad restringida por bloque).

La nota anterior, aunque técnica, es importante así que vamos a dar algunos detalles al respecto. P. ej. el siguiente código produce un error:

var g = 10; var f = function() {

 console.log(g); 
 let g=20;

} f(); ReferenceError al acceder a g antes de su declaración Dentro de la función f, el console.log debería imprimir el valor 10 si no hubiera realmente hoisting (observa que si g estuviese definida con var y no con let el console.log imprimiría “undefined” y no daría error, precisamente por el hoisting). Pero, realmente hay hoisting de la variable g, por lo que este console.log no imprime el valor de la variable global, sino que lo hace de la variable local (definida más abajo). Pero al estar definida con let, el valor obtenido por el hoisting no es indefinidio sino que es no válido, ya que la variable está en su dead zone. Así, al acceder a ella obtenemos el ReferenceError. Por simplificación leerás en muchos sitios que las variables declaradas con let no sufren del hoisting, pero es un poco “aceptamos pulpo”: como simplificación sirve, pero no es exacto. Ahora ya sabes qué sucede con exactitud. Ámbito de bloque El ámbito de bloque implica que una variable declarada dentro de un bloque de código (tal y como un for o un if) es visible y existe solo dentro de ese bloque de código. Eso evita posibles errores y además puede disminuir el consumo de memoria: cuando se sale de un bloque de código, todos los objetos creados en él, pueden ser destruidos (ya que pasarán a ser inaccesibles). Como hemos visto, si se accede a una variable declarada con let antes de su declaración, se obtiene un error de referencia. Este comportamiento es como, si para las variables declaradas con let, se aplicase el modo estricto (en el sentido de que se nos impide acceder a una variable no declarada). Por ello algunos entornos de ECMAScript (como V8 usada, entre otros, por Chrome y NodeJS) no permiten usar let sin el modo estricto. Así el siguiente código da error de referencia: 'use strict'; function foo() { var sum = 0; for (let i=0; i< 10; i++) { sum += i; } console.log('iters →' + i + ' result ' + sum); Error de referencia: i ya no existe en este punto } foo(); El siguiente código da error también: console.log(v); let v=10; En este caso, al intentar acceder a la variable v antes de su declaración provoca un error, ya que la variable es como si no existiese (está en su dead zone tal y como hemos analizado antes). Declaraciones let duplicadas A diferencia de var, una variable declarada con let no puede ser declarada dos veces. El siguiente código funciona correctamente e imprime el valor 20 en la consola: function foo() { var a=10; var a=20; console.log(a); } foo(); Pero el mismo código usando let en lugar de var genera un error: Error al redeclarar una variable con let. De hecho es importante resaltar que el error se da incluso sin llamar a la función foo , ya que no es un error de ejecución sino que se produce en la fase de análisis semántico.

informatica/programacion/cursos/programacion_avanzada_javascript/declaracion_variables_let_const.1728900624.txt.gz · Última modificación: por tempwin