Si queremos programar en Angular 2, vamos a entender primero algunas características peculiares de la especificación ES6 que nos pueden dar algún que otro quebradero de cabeza.
Hasta ahora, para declarar una variable en Javascript usábamos var. En ES6 se incluye let. ¿Cuál es la diferencia entre ambas?
La primera diferencia es que var no tiene ámbito de bloque, mientras que let sí que lo tiene. ¿Qué significa esto? Veamos un ejemplo sencillo:
"use strict"; var a=5; if(true) { var a = 7; } console.log(a); // 7
En este caso, al no tener ámbito de bloque, nuestra variable es accesible desde el nivel superior, con lo que se queda con el valor que le hemos asignado en el bloque if. Sin embargo, si utilizamos let en vez de var:
"use strict"; let a=5; if(true) { let a = 7; console.log(a); // 7 } console.log(a); // 5
El resultado se mantiene con los ámbitos adecuados.
Una segunda característica es que si usamos let, la variable no es izada... ¿Izada?
Empecemos con este ejemplo:
"use strict"; var a = 5; (function(){ console.log(a); })(); // Salida: 5
Muy bien; dentro de la función encontramos a la variable a en su cadena de ámbito e imprimimos su valor, 5. Vamos a retorcer un poco el ejemplo:
"use strict"; var a = 5; (function(){ console.log(a); var a = 7; console.log(a); })(); // Salida: undefined // Salida: 7
Ayayay... ¿Por qué la primera salida es undefined? ¿No debería es en todo caso 5?
El problema es lo que se conoce como javascript "hoisting", o izado de variable. En alguna ocasión me he encontrado con el simil de que las variables actúan como burbujas que se elevan hasta la parte superior del ámbito correspondiente.
Lo que en realidad ocurre (investigué porque el simil burbujil nunca lo llegué a comprender) es que el intérprete de javascript, cuando necesita un nuevo contexto de ejecución, recorre dicho ámbito para almacenar las declaraciones de variables y funciones antes de empezar a ejecutar el código.
En el ejemplo, cuando llamamos a la función, el intérprete ve que se ha declarado una variable (ahora mismo la asignación no es importante) y la guarda en el contexto de ejecución. Ahora quiere imprimir el contenido de la variable a, que ha sido declarada en el contexto de ejecución de la función pero no tiene valor asignado (aún), con lo que obtenemos un undefined. El siguiente paso de programación le da un valor a la variable y al siguiente imprime dicho valor, que es 7.
¿Qué ocurre si cambiamos var por let?
"use strict"; let a = 5; (function(){ console.log(a); let a = 7; console.log(a); })(); // Error
Esto nos dará un error de referencia que nos indicará que la variable a no está definida. En este caso, el intérprete sabe vamos a declarar una variable en el ámbito de la función (indicada en su contexto de ejecución), pero ahora no se iza la variable, de manera que en el momento en que queremos mostrar su contenido, la variable aún no ha sido declarada; de ahí el error.