Novedades en JavaScript 1.7

  • Enlace amigable (slug) de la revisión: Novedades_en_JavaScript_1.7
  • Título de la revisión: Novedades en JavaScript 1.7
  • Id de la revisión: 162133
  • Creada:
  • Creador: Superruzafa
  • ¿Es la revisión actual? No
  • Comentario /* Destructuring assignment */

Contenido de la revisión

{{wiki.template('Traducción', [ "inglés", "New in JavaScript 1.7", "en" ])}}

JavaScript 1.7 es una actualización del lenguaje introduciendole varias características nuevas, como generadores, iteradores, comprension de arrays, sentencias let y asignación desestructurada. Evidentemente también incluye todas las características de JavaScript 1.6.

El soporte para JavaScript 1.7 estará disponible a partir de Firefox 2 Beta 1, así como en construcciones actuales.

Los ejemplos de código incluídos en este artículo pueden ser probados en la consola JavaScript. Si quiere aprender a construir o utilizar esta consola, lea Introducción a la shell JavaScript.

Utilizando JavaScript 1.7

Para usar las nuevas caracteristicas de JavaScript 1.7, es necesario especificar explícitamente el uso de JavaScript 1.7. En HTML o XUL, utilice:

 <script type="application/javascript;version=1.7"/>

Cuando utilice Shell de JavaScript, debe especificar la versión deseada utilizando la función version():

 version(170);

Generadores e iteradores

Cuando se desarrolla código que involucra algoritmos iterativos (como iteraciones sobre listas, o cálculos repetitivos sobre el mismo conjunto de datos), con frecuencia hay variables de estado cuyos valores necesitan ser mantenidos durante el proceso. Tradicionalmente se utilizan funciones callback para obtener los valores intermedios de un algoritmo iterativo.


Generadores

Considere este algoritmo iterativo que obtiene los numeros de la serie Fibonacci:

function do_callback(num) {
  document.write(num + "<BR>\n");
}

function fib() {
  var i = 0, j = 1, n = 0;
  while (n < 10) {
    do_callback(i);
    var t = i;
    i = j;
    j += t;
    n++;
  }
}

fib();

Este codigo utiliza rutinas callback para realizar las operaciones en cada paso del algoritmo. En este caso, cada numero Fibonacci es impreso en la consola.

Los generadores e iteradores trabajan juntos apra proveer nuevas y mejores formas de hacer esto. Veamos como es la rutina de la serie Fibonacci escrita utilizando generadores:


function fib() {
  var i = 0, j = 1;
  while (true) {
    yield i;
    var t = i;
    i = j;
    j += t;
  }
}

var g = fib();
for (var i = 0; i < 10; i++) {
  document.write(g.next() + "<BR>\n");
}

La función contieniendo la palabra clave yield es un generador. Cuando lo llamas, sus parámetros formales son atados a los argumentos actuales, pero su cuerpo no es evaluado realmente. En cambio, un generator-iterator es devuelto. Cada llamada al método del generator-iterator next() realiza otro paso a través del algoritmos iterativo. Cada valor de pasos es el valor especificado por la palabra clave yield. Piensa en yield como la versión generator-iterator de return, indicando la frontera entre cada iteración del algoritmo. Cada vez que llames next(), el código generador resume la declaración siguiendo el yield.

You cycle a generator-iterator by repeatedly calling its next() method until you reach your desired result condition. In this example, we can obtain however many Fibonacci numbers we want by continuing to call g.next() until we have the number of results we want.

Iteradores

Un iterador es un objeto especial que te permite iterar datos.

En el uso cotidiano, los objetos iteradores son invisibles (no se necesita trabajar con ellos explícitamente) y son usados en sentencias for...in y for each...in para recorrer de forma natural las claves y/o los valores de los objetos.

var objectWithIterator = getObjectSomehow();

for (var i in objectWithIterator)
{
  document.write(objectWithIterator[i] + "<BR>\n");
}

Si se está implementando un objeto iterador personalizado o se necesita manipular directamente un iterador, será preciso conocer antes el método next(), la excepción StopIteration y la propiedad __iterator__.

traduzco getter como la función get Se puede crear un iterador para un objeto llamando a Iterator(objectname). El iterador para cierto objeto se conoce gracias a la propiedad __iterator__ de dicho objeto, la cual implementa predeterminadamente la iteración de acuerdo al modelo convencional de for..in y for each...in. Si se desea utilizar un iterador personalizado, se debería sobreescribir la función get para que __iterator__ devuelva una instancia del susodicho iterador. Para obtener el iterador de un objeto en un script se debería de usar Iterator(obj) en lugar de acceder directamente a la propiedad __iterator__.

Una vez se tiene el iterador, se puede buscar fácilmente el siguiente elemento en el objeto llamando su método next(). Cuando no hay más datos se lanza la excepción StopIteration.

A continuación se muestra un ejemplo simple de manipulación directa de iteradores:

var obj = {name:"Jack Bauer", username:"JackB", id:12345, agency:"CTU", region:"Los Angeles"};

var it = Iterator(obj);

try {
  while (true) {
    document.write(it.next() + "<BR>\n");
  }
} catch (err if err instanceof StopIteration) {
  document.write("End of record.<BR>\n");
} catch (err) {
  document.write("Unknown error: " + err.description + "<BR>\n");
}

La salida de este programa tendrá este aspecto:

name,Jack Bauer
username,JackB
id,12345
agency,CTU
region,Los Angeles
End of record.

Opcionalmente se puede especificar un segundo parámetro durante la creación del iterador, el cual es un valor booleano que indica si sólo se quieren obtener las claves cada vez que se llama al método next() o no. Cambiando var it = Iterator(obj); por var it = Iterator(obj, true); en el ejemplo anterior se obtendría la siguiente salida:

name
username
id
agency
region
End of record.

En ambos casos, el orden final en el que los datos son devueltos puede variar dependiendo de la implementación por lo que no se garantiza el orden de los datos.

Los iteradores son un método útil de recorrer los datos de los objetos, incluyendo objetos que pueden contener datos inesperados. Esto puede ser especialmente útil si se necesitan recuperar datos para los que la aplicación no está preparada.

Comprensión de arrays

La comprensión de arrays es una forma de utilizar generadores para realizar de manera apropiada potentes inicializaciones de arrays. Por ejemplo:

function range(begin, end) {
  for (let i = begin; i < end; ++i) {
    yield i;
  }
}

range() es un generador que devuelve todos los valores entre <tt>begin</tt> y <tt>end</tt>. Una vez definido eso, se puede utilizar así:

var diez_cuadrados = [i * i for (i in range(0, 10))];

Esto pre-inicializa un nuevo array, diez_cuadrados, para que contenga los cuadrados de los valores del rango 0..9.

Se puede usar cualquier sentencia condicional al inicializar un array. Si lo que se quiere es inicializar un array para que contenta los números pares entre 0 y 20, se puede usar este código.

var pares = [i for (i in range(0, 21)) if (i % 2 == 0)];

Antes de JavaScript 1.7, lo anterior debería haber sido codificado así:

var evens = [];
for (var i=0; i <= 20; i++) {
  if (i % 2 == 0)
    evens.push(i);
}

La comprensión de arrays no sólo es mucho más compacta sino que de hecho es mucho más fácil de leer una vez que nos hemos familiarizado con el concepto.

Reglas de ámbito

La comprensión de arrays utiliza un bloque implícito en el cual se ubica. Dicho bloque contiene todo el contenido que se halla dentro de los corchetes, además del las declaraciones let implícitas.

''Add details.''

Ámbito del bloque con let

Ámbito de un bloque con let

Existen varias formas en las que let puede ser usado para manejar el ámbito de un bloque de datos y funciones:

  • La sentencia let proporciona un método de asociar valores con variables, constantes y funciones en el ámbito del bloque, sin afectar a los de las variables que tengan el mismo nombre fuera del bloque.
  • La expresión let permite establecer variables cuyo ámbito está comprendido en una única expresión.
  • La definición let define variables, constantes y funciones cuyo ámbito queda restringido al bloque en el que se han definido. Esta sintaxis es muy parecida a la usada para var.
  • Además se puede utilizar let para establecer variables que existan sólo dentro del contexto de un bucle for.


El sentencia let

La sentencia let proporciona un ámbito local para variables, constantes y funciones. Funciona reservando cero o más variables en el ámbito léxico de un único bloque de código. La validez de la sentencia let finaliza cuando termina el bloque.

Por ejemplo:

var x = 5;
var y = 0;

let (x = x+10, y = 12) {
  document.write(x+y + "<BR>\n");
}

document.write(x+y + "<BR>\n");

tendrá como salida:

27
5

Las reglas para el bloque de código son las mismas que para cualquier otro bloque de código de JavaScript. Puede tener sus propias variables establecidas usando declaraciones let.

Nota: Cuando se use la sintaxis de las sentencia let, será necesario incluir los paréntesis. El no incluirlos provocará un error de sintaxis.

Reglas de ámbito

El ámbito de las variables definidas usando let es el del mismo bloque de let, además de cualquier bloque interno contenido dentro de él, a menos que esos bloques definan variables con el mismo nombre.

Expresiones let

Se puede usar let para establecer variables cuyo ámbito comprende sólo una única expresión:

var x = 5;
var y = 0;
document.write( let(x = x + 10, y = 12) x+y  + "<BR>\n");
document.write(x+y + "<BR>\n");

La salida da como resultado:

27
5

En este caso, el ámbito de las variables x = x+10 e y = 12 es utilizado solamente en la expresión x+y

Reglas de ámbito

Dada la expresión let

let (decls) expr

existe un bloque creado implícitamente que comprende el trozo expr.

Definiciones let

La palabra clave let puede además ser usada para definir variables, constantes y funciones dentro de un bloque.

 ** Este código no funciona en FF 2.0 b1. **
if (x > y)
{
   let const k = 37;
   let gamma : int = 12.7 + k;
   let i = 10;
   let function f(n) { return (n/3)+k; }
   return f(gamma) + f(i);
}

Reglas de ámbito

Las variables, funciones y constantes declaradas usando let, let function y let const tienen como ámbito el bloque en el que están definidas, además de cualquier sub-bloque en el que no sean redefinidas. De este modo, let funciona como var.

En los programas y clases, let no crea propiedades en los objetos y clases globales como hace var. En vez de eso, crea propiedades en un bloque implícito creado para la evaluación de sentencias en dichos contextos. Esto significa esencialmente que let no sobreescribirá las variables previamente definidas usando var. Por ejemplo:

** No funciona en FF 2.0 b1. Devuelve "42", no "global".
var x = 'global';
let x = 42;
document.write(this.x + "<BR>\n");

La salida mostrada por este código será "global", no "42".

Un bloque implícito es aquel que no está comprendido entre llaves; es creado implícitamente por el motor de JavaScript.

En las funciones, una sentencia let ejecutada dentro de eval() no crea propiedades en el objeto variable Esto hay que traducirlo: (activation object or innermost binding rib) como sí hace var. En vez de eso, lo hace en un bloque creado implícitamente para la evaluación de las sentencias del programa. Esto es consecuencia de la forma de trabajar de eval() unido a la anterior regla.

En otras palabras, cuando se usa eval() para ejecutar código, dicho código es es tratado como un programa independiente el cual tiene su propio bloque implícito alrededor de su código.

Ámbito de variables con let en bucles for

Se puede usar la palabra reservada let para declarar variables localmente en el ámbito de un bucle for, al igual que con var.

** Add obj **
   var i=0;
   for ( let i=i ; i < 10 ; i++ )
     document.write(i + "<BR>\n");

   for ( let [name,value] in obj )
     document.write("Name: " + name + ", Value: " + value + "<BR>\n");

Reglas de ámbito

for (let expr1; expr2; expr3) sentencia

En este ejemplo, expr2, expr3 y sentencia están delimitadas por un bloque implícito que contiene a las variables locales al bloque declaradas por let expr1. Esto se demuestra en el primer bucle del ejemplo.

for (expr1 in expr2) sentencia

En este caso, existe un bloque implícito que contiene a sentencia. Esto es mostrado en el segundo bucle del ejemplo.

Asignación desestructurada

La asignación desestructurada hace posible extraer datos desde arrays u objetos utilizando una sintaxis que refleja la construcción de arrays y objetos literales.

Las expresiones de objetos y arrays literales proporcionan una forma fácil de crear paquetes de datos ad hoc. Una vez creados estos paquetes de datos, pueden ser usados como se quiera. Se pueden devolver incluso desde funciones.

Una peculiaridad especialmente útil que se puede hacer con la asignación desestructurada es leer una estructura completa desde una única sentencia aunque hay un número de cosas interesantes que se pueden hacer con ella, como muestra la siguiente sección repleta de ejemplos.

Esta capacidad es similar a las características que presentan lenguajes tales como Perl o Python.

Ejemplos

La asignación desestructurada se explica mejor con ejemplos por lo que aquí se muestran un par de ellos con fines didáctico.

Nota: Si tienes ejemplos más interesantes con formas de utilizar la asignación desestructurada, por favor, anímate a añadirlos a esta sección.

Intercambiando valores

Se puede usar la asignación desestructurada para, por ejemplo, intercambiar valores:

var a = 1;
var b = 3;

[a, b] = [b, a];

Tras ejecutar este código, b valdrá 1 y a valdrá 3.

O para rotar valores: (formato de código pobre)

<body bgcolor = "black">

<script type="application/javascript;version=1.7"/>

var a = 'o';
var b = "<font color = 'green'>o</font>";
var c = 'o';
var d = 'o';
var e = 'o';
var f = "<font color = 'blue'>o</font>";
var g = 'o';
var h = 'o';

for (lp=0;lp<40;lp++)
	{[a, b, c, d, e, f, g, h] = [b, c, d, e, f, g, h, a];
	 document.write(a+''+b+''+c+''+d+''+e+''+f+''+g+''+h+''+"<br />");}
</script>

Después de ejecutar este código, se mostrará un espectáculo de colores gracias a la rotación de las variables.

Devolviendo múltiples valores

Gracias a la asignación desestructurada, las funciones pueden devolver múltiples valores. Dado que las funciones siempre han podido devolver funciones, ésto proporciona una vuelta de tuerca a la flexibilidad.

function f() {
  return [1, 2];
}

Como se puede observar, los resultados se devuelven usando una notación parecida a la utilizada con los arrays, con los valores que se quieren devolver encerrados entre corchetes. Así, se puede devolver un número cualquiera de resultados. En el siguiente ejemplo, f() devuelve el valor {{mediawiki.external('1, 2')}}.

var a, b;
[a, b] = f();
document.write ("A es " + a + " B es " + b + "<BR>\n");

El comando {{mediawiki.external('a, b')}} = f() asigna el resultado de la función a las variables ubicadas por orden entre corchetes: a queda establecido a 1 y b a 2.

También se pueden obtener los valores devueltos como un array:

var a = f();
document.write ("A es " + a);

En este caso, a será un array que contendrá los valores 1 y 2.

Ignorar ciertos valores devueltos

Se pueden ignorar algunos valores devueltos en los que no se esté interesado:

function f() {
  return [1, 2, 3];
}

var [a, , b] = f();
document.write ("A is " + a + " B is " + b + "<BR>\n");

Tras ejecutar este código, a valdrá 1 y b, 3. El valor 2 es ignorado.

Iteración sobre objetos

Se puede usar asignación desestructurada para recuperar datos de un objeto.

var obj = { nombre: "Bob", puntos: 1.5, edad: 35 };

for (let[nombre, valor] in obj) {
  document.write ("Nombre: " + nombre + ", Valor: " + valor + "<BR>\n");
}

Este bucle recorre todos los pares clave/valor del objeto obj y muestra sus nombres y valores. En este caso, la salida será algo así:

Nombre: nombre, Valor: Bob
Nombre: puntos, Valor: 1.5
Nombre: edad, Valor: 35

Iteración sobre valores en arrays de objetos

Se puede iterar un array de objetos, accediendo a los campos que interesen de cada objeto.

var personas  = [
  {
    nombre: "Mike Smith",
    familia: {
      madre: "Jane Smith",
      padre: "Harry Smith",
      hermana: "Samantha Smith"
    },
    edad: 35
  },
  {
    nombre: "Tom Jones",
    familia: {
      madre: "Norah Jones",
      padre: "Richard Jones",
      hermano: "Howard Jones"
    },
    edad: 25
  }
];

for each (let {nombre: n, familia: { padre: f } } in personas) {
  document.write ("Nombre: " + n + ", Padre: " + f + "<BR>\n");
}

Esto copia el valor del campo nombre a n y el del campo familia.padre a f y luego los muestra por pantalla. Esto se hace para cada objeto del array personas. La salida será algo así:

Nombre: Mike Smith, Padre: Harry Smith
Nombre: Tom Jones, Padre: Richard Jones
{{ wiki.languages( { "en": "en/New_in_JavaScript_1.7", "fr": "fr/Nouveaut\u00e9s_dans_JavaScript_1.7", "pl": "pl/Nowo\u015bci_w_JavaScript_1.7" } ) }}

Fuente de la revisión

<p>{{wiki.template('Traducción', [ "inglés", "New in JavaScript 1.7", "en" ])}}
</p><p>JavaScript 1.7 es una actualización del lenguaje introduciendole varias características nuevas, como generadores, iteradores, comprension de arrays, sentencias <code>let</code> y asignación desestructurada. Evidentemente también incluye todas las características de <a href="es/Novedades_en_JavaScript_1.6">JavaScript 1.6</a>.
</p><p>El soporte para JavaScript 1.7 estará disponible a partir de <a href="es/Firefox_2">Firefox 2</a> Beta 1, así como en construcciones actuales.
</p><p>Los ejemplos de código incluídos en este artículo pueden ser probados en la consola JavaScript. Si quiere aprender a construir o utilizar esta consola, lea <a href="es/Introducci%c3%b3n_a_la_shell_JavaScript">Introducción a la shell JavaScript</a>.
</p>
<h2 name="Utilizando_JavaScript_1.7">Utilizando JavaScript 1.7</h2>
<p>Para usar las nuevas caracteristicas de JavaScript 1.7, es necesario especificar explícitamente el uso de JavaScript 1.7. En HTML o XUL, utilice:
</p>
<pre class="eval"> &lt;script type="application/javascript;version=1.7"/&gt;
</pre>
<p>Cuando utilice <a href="es/Introduccion_al_shell_de_JavaScript">Shell de JavaScript</a>, debe especificar la versión deseada utilizando la función <code>version()</code>:
</p>
<pre class="eval"> version(170);
</pre>
<h2 name="Generadores_e_iteradores">Generadores e iteradores</h2>
<p>Cuando se desarrolla código que involucra algoritmos iterativos (como iteraciones sobre listas, o cálculos repetitivos sobre el mismo conjunto de datos), con frecuencia hay variables de estado cuyos valores necesitan ser mantenidos durante el proceso. Tradicionalmente se utilizan funciones callback para obtener los valores intermedios de un algoritmo iterativo.
</p><p><br>
</p>
<h3 name="Generadores">Generadores</h3>
<p>Considere este algoritmo iterativo que obtiene los numeros de la serie Fibonacci:
</p>
<pre>function do_callback(num) {
  document.write(num + "&lt;BR&gt;\n");
}

function fib() {
  var i = 0, j = 1, n = 0;
  while (n &lt; 10) {
    do_callback(i);
    var t = i;
    i = j;
    j += t;
    n++;
  }
}

fib();
</pre>
<p>Este codigo utiliza rutinas callback para realizar las operaciones en cada paso del algoritmo. En este caso, cada numero Fibonacci es impreso en la consola.
</p><p>Los generadores e iteradores trabajan juntos apra proveer nuevas y mejores formas de hacer esto. Veamos como es la rutina de la serie Fibonacci escrita utilizando generadores:
</p><p><br>
</p>
<pre>function fib() {
  var i = 0, j = 1;
  while (true) {
    yield i;
    var t = i;
    i = j;
    j += t;
  }
}

var g = fib();
for (var i = 0; i &lt; 10; i++) {
  document.write(g.next() + "&lt;BR&gt;\n");
}
</pre>
<p>La función contieniendo la palabra clave <code>yield</code> es un generador. Cuando lo  llamas, sus parámetros formales son atados a los argumentos actuales, pero su cuerpo no es evaluado realmente. En cambio, un <i>generator-iterator</i> es devuelto. Cada llamada al método del <i>generator-iterator</i> <code>next()</code> realiza otro paso a través del algoritmos iterativo. Cada valor de pasos es el valor especificado por la palabra clave <code>yield</code>. Piensa en <code>yield</code> como la versión <i>generator-iterator</i> de <code>return</code>, indicando la frontera entre cada iteración del algoritmo. Cada vez que llames <code>next()</code>, el código generador resume la declaración siguiendo el <code>yield</code>.
</p><p>You cycle a generator-iterator by repeatedly calling its <code>next()</code> method until you reach your desired result condition.  In this example, we can obtain however many Fibonacci numbers we want by continuing to call <code>g.next()</code> until we have the number of results we want.
</p>
<h3 name="Iteradores"> Iteradores </h3>
<p>Un <i>iterador</i> es un objeto especial que te permite iterar datos.
</p><p>En el uso cotidiano, los objetos iteradores son <i>invisibles</i> (no se necesita trabajar con ellos explícitamente) y son usados en <a href="es/Core_JavaScript_1.5_Guide/Object_Manipulation_Statements">sentencias <code>for...in</code> y <code>for each...in</code></a> para recorrer de forma natural las claves y/o los valores de los objetos.
</p>
<pre>var objectWithIterator = getObjectSomehow();

for (var i in objectWithIterator)
{
  document.write(objectWithIterator[i] + "&lt;BR&gt;\n");
}
</pre>
<p>Si se está implementando un objeto iterador personalizado o se necesita manipular directamente un iterador, será preciso conocer antes el método <code>next()</code>, la excepción <code>StopIteration</code> y la propiedad <code>__iterator__</code>.
</p><p><span class="comment">traduzco getter como la función get</span>
Se puede crear un iterador para un objeto llamando a <code>Iterator(<i>objectname</i>)</code>. El iterador para cierto objeto se conoce gracias a la propiedad <code>__iterator__</code> de dicho objeto, la cual implementa predeterminadamente la iteración de acuerdo al modelo convencional de <code>for..in</code> y <code>for each...in</code>. Si se desea utilizar un iterador personalizado, se debería sobreescribir la función <a href="es/Core_JavaScript_1.5_Guide/Creating_New_Objects/Defining_Getters_and_Setters">get</a> para que <code>__iterator__</code> devuelva una instancia del susodicho iterador. Para obtener el iterador de un objeto en un script se debería de usar <code>Iterator(<i>obj</i>)</code> en lugar de acceder directamente a la propiedad <code>__iterator__</code>.
</p><p>Una vez se tiene el iterador, se puede buscar fácilmente el siguiente elemento en el objeto llamando su método <code>next()</code>. Cuando no hay más datos se lanza la excepción <code>StopIteration</code>.
</p><p>A continuación se muestra un ejemplo simple de manipulación directa de iteradores:
</p>
<pre>var obj = {name:"Jack Bauer", username:"JackB", id:12345, agency:"CTU", region:"Los Angeles"};

var it = Iterator(obj);

try {
  while (true) {
    document.write(it.next() + "&lt;BR&gt;\n");
  }
} catch (err if err instanceof StopIteration) {
  document.write("End of record.&lt;BR&gt;\n");
} catch (err) {
  document.write("Unknown error: " + err.description + "&lt;BR&gt;\n");
}
</pre>
<p>La salida de este programa tendrá este aspecto:
</p>
<pre>name,Jack Bauer
username,JackB
id,12345
agency,CTU
region,Los Angeles
End of record.
</pre>
<p>Opcionalmente se puede especificar un segundo parámetro durante la creación del iterador, el cual es un valor booleano que indica si sólo se quieren obtener las claves cada vez que se llama al método <code>next()</code> o no. Cambiando <code>var it = Iterator(obj);</code> por <code>var it = Iterator(obj, true);</code> en el ejemplo anterior se obtendría la siguiente salida:
</p>
<pre>name
username
id
agency
region
End of record.
</pre>
<p>En ambos casos, el orden final en el que los datos son devueltos puede variar dependiendo de la implementación por lo que <b>no se garantiza el orden de los datos</b>.
</p><p>Los iteradores son un método útil de recorrer los datos de los objetos, incluyendo objetos que pueden contener datos inesperados. Esto puede ser especialmente útil si se necesitan recuperar datos para los que la aplicación no está preparada.
</p>
<h2 name="Comprensi.C3.B3n_de_arrays"> Comprensión de arrays </h2>
<p>La comprensión de arrays es una forma de utilizar generadores para realizar de manera apropiada potentes inicializaciones de arrays. Por ejemplo:
</p>
<pre class="eval">function range(begin, end) {
  for (let i = begin; i &lt; end; ++i) {
    yield i;
  }
}
</pre>
<p><code>range()</code> es un generador que devuelve todos los valores entre <tt>begin</tt> y <tt>end</tt>. Una vez definido eso, se puede utilizar así:
</p>
<pre class="eval">var diez_cuadrados = [i * i for (i in range(0, 10))];
</pre>
<p>Esto pre-inicializa un nuevo array, <var>diez_cuadrados</var>, para que contenga los cuadrados de los valores del rango <code>0..9</code>.
</p><p>Se puede usar cualquier sentencia condicional al inicializar un array. Si lo que se quiere es inicializar un array para que contenta los números pares entre 0 y 20, se puede usar este código.
</p>
<pre class="eval">var pares = [i for (i in range(0, 21)) if (i % 2 == 0)];
</pre>
<p>Antes de JavaScript 1.7, lo anterior debería haber sido codificado así:
</p>
<pre>var evens = [];
for (var i=0; i &lt;= 20; i++) {
  if (i % 2 == 0)
    evens.push(i);
}
</pre>
<p>La comprensión de arrays no sólo es mucho más compacta sino que de hecho es mucho más fácil de leer una vez que nos hemos familiarizado con el concepto.
</p>
<h4 name="Reglas_de_.C3.A1mbito"> Reglas de ámbito </h4>
<p>La comprensión de arrays utiliza un bloque implícito en el cual se ubica. Dicho bloque contiene todo el contenido que se halla dentro de los corchetes, además del las declaraciones <code>let</code> implícitas.
</p><p><span class="comment">''Add details.''</span>
</p>
<h2 name=".C3.81mbito_del_bloque_con_let"> Ámbito del bloque con <code>let</code> </h2>
<h2 name=".C3.81mbito_de_un_bloque_con_let"> Ámbito de un bloque con <code>let</code> </h2>
<p>Existen varias formas en las que <code>let</code> puede ser usado para manejar el ámbito de un bloque de datos y funciones:
</p>
<ul><li> La <b>sentencia <code>let</code></b> proporciona un método de asociar valores con variables, constantes y funciones en el ámbito del bloque, sin afectar a los de las variables que tengan el mismo nombre fuera del bloque.
</li><li> La <b>expresión <code>let</code></b> permite establecer variables cuyo ámbito está comprendido en una única expresión.
</li><li> La <b>definición <code>let</code></b> define variables, constantes y funciones cuyo ámbito queda restringido al bloque en el que se han definido. Esta sintaxis es muy parecida a la usada para <code>var</code>.
</li><li> Además se puede utilizar <code>let</code> para establecer variables que existan sólo dentro del contexto de un bucle <code>for</code>.
</li></ul>
<p><br>
</p>
<h3 name="El_sentencia_let"> El sentencia <code>let</code> </h3>
<p>La sentencia <code>let</code> proporciona un ámbito local para variables, constantes y funciones. Funciona reservando cero o más variables en el ámbito léxico de un único bloque de código. La validez de la sentencia <code>let</code> finaliza cuando termina el bloque.
</p><p>Por ejemplo:
</p>
<pre>var x = 5;
var y = 0;

let (x = x+10, y = 12) {
  document.write(x+y + "&lt;BR&gt;\n");
}

document.write(x+y + "&lt;BR&gt;\n");
</pre>
<p>tendrá como salida:
</p>
<pre>27
5
</pre>
<p>Las reglas para el bloque de código son las mismas que para cualquier otro bloque de código de JavaScript. Puede tener sus propias variables establecidas usando declaraciones <code>let</code>.
</p>
<div class="note"><b>Nota:</b> Cuando se use la sintaxis de las sentencia <code>let</code>, será necesario incluir los paréntesis. El no incluirlos provocará un error de sintaxis.</div>
<h4 name="Reglas_de_.C3.A1mbito_2"> Reglas de ámbito </h4>
<p>El ámbito de las variables definidas usando <code>let</code> es el del mismo bloque de <code>let</code>, además de cualquier bloque interno contenido dentro de él, a menos que esos bloques definan variables con el mismo nombre.
</p>
<h3 name="Expresiones_let"> Expresiones <code>let</code> </h3>
<p>Se puede usar <code>let</code> para establecer variables cuyo ámbito comprende sólo una única expresión:
</p>
<pre>var x = 5;
var y = 0;
document.write( let(x = x + 10, y = 12) x+y  + "&lt;BR&gt;\n");
document.write(x+y + "&lt;BR&gt;\n");
</pre>
<p>La salida da como resultado:
</p>
<pre>27
5
</pre>
<p>En este caso, el ámbito de las variables <var>x</var> = <code>x+10</code> e <var>y</var> = <code>12</code> es utilizado solamente en la expresión <code>x+y</code>
</p>
<h4 name="Reglas_de_.C3.A1mbito_3"> Reglas de ámbito </h4>
<p>Dada la expresión <code>let</code>
</p>
<pre class="eval">let (<var>decls</var>) <var style="color: blue">expr</var>
</pre>
<p>existe un bloque creado implícitamente que comprende el trozo <var style="color: blue">expr</var>.
</p>
<h3 name="Definiciones_let"> Definiciones <code>let</code> </h3>
<p>La palabra clave <code>let</code> puede además ser usada para definir variables, constantes y funciones dentro de un bloque.
</p>
<pre> ** Este código no funciona en FF 2.0 b1. **
if (x &gt; y)
{
   let const k = 37;
   let gamma : int = 12.7 + k;
   let i = 10;
   let function f(n) { return (n/3)+k; }
   return f(gamma) + f(i);
}
</pre>
<h4 name="Reglas_de_.C3.A1mbito_4"> Reglas de ámbito </h4>
<p>Las variables, funciones y constantes declaradas usando <code>let</code>, <code>let function</code> y <code>let const</code> tienen como ámbito el bloque en el que están definidas, además de cualquier sub-bloque en el que no sean redefinidas. De este modo, <code>let</code> funciona como <code>var</code>.
</p><p>En los programas y clases, <code>let</code> no crea propiedades en los objetos y clases globales como hace <code>var</code>. En vez de eso, crea propiedades en un bloque implícito creado para la evaluación de sentencias en dichos contextos. Esto significa esencialmente que <code>let</code> no sobreescribirá las variables previamente definidas usando <code>var</code>. Por ejemplo:
</p>
<pre>** No funciona en FF 2.0 b1. Devuelve "42", no "global".
var x = 'global';
let x = 42;
document.write(this.x + "&lt;BR&gt;\n");
</pre>
<p>La salida mostrada por este código será "global", no "42".
</p><p>Un <i>bloque implícito</i> es aquel que no está comprendido entre llaves; es creado implícitamente por el motor de JavaScript.
</p><p>En las funciones, una sentencia <code>let</code> ejecutada dentro de <code>eval()</code> no crea propiedades en el objeto variable <span class="comment">Esto hay que traducirlo: (activation object or innermost binding rib)</span> como sí hace <code>var</code>. En vez de eso, lo hace en un bloque creado implícitamente para la evaluación de las sentencias del programa. Esto es consecuencia de la forma de trabajar de <code>eval()</code> unido a la anterior regla.
</p><p>En otras palabras, cuando se usa <code>eval()</code> para ejecutar código, dicho código es es tratado como un programa independiente el cual tiene su propio bloque implícito alrededor de su código.
</p>
<h3 name=".C3.81mbito_de_variables_con_let_en_bucles_for"> Ámbito de variables con <code>let</code> en bucles <code>for</code> </h3>
<p>Se puede usar la palabra reservada <code>let</code> para declarar variables localmente en el ámbito de un bucle <code>for</code>, al igual que con <code>var</code>.
</p>
<pre>** Add obj **
   var i=0;
   for ( let i=i ; i &lt; 10 ; i++ )
     document.write(i + "&lt;BR&gt;\n");

   for ( let [name,value] in obj )
     document.write("Name: " + name + ", Value: " + value + "&lt;BR&gt;\n");
</pre>
<h4 name="Reglas_de_.C3.A1mbito_5"> Reglas de ámbito </h4>
<pre class="eval">for (let <var>expr1</var>; <var style="color: blue">expr2</var>; <var style="color: blue">expr3</var>) <var style="color: blue">sentencia</var>
</pre>
<p>En este ejemplo, <var style="color: blue">expr2</var>, <var style="color: blue">expr3</var> y <var style="color: blue">sentencia</var> están delimitadas por un bloque implícito que contiene a las variables locales al bloque declaradas por <code>let <var>expr1</var></code>. Esto se demuestra en el primer bucle del ejemplo.
</p>
<pre class="eval">for (<var>expr1</var> in <var>expr2</var>) <var style="color: blue">sentencia</var>
</pre>
<p>En este caso, existe un bloque implícito que contiene a <var style="color: blue">sentencia</var>. Esto es mostrado en el segundo bucle del ejemplo.
</p>
<h2 name="Asignaci.C3.B3n_desestructurada"> Asignación desestructurada </h2>
<p>La asignación desestructurada hace posible extraer datos desde arrays u objetos utilizando una sintaxis que refleja la construcción de arrays y objetos literales.
</p><p>Las expresiones de objetos y arrays literales proporcionan una forma fácil de crear paquetes de datos ad hoc. Una vez creados estos paquetes de datos, pueden ser usados como se quiera. Se pueden devolver incluso desde funciones.
</p><p>Una peculiaridad especialmente útil que se puede hacer con la asignación desestructurada es leer una estructura completa desde una única sentencia aunque hay un número de cosas interesantes que se pueden hacer con ella, como muestra la siguiente sección repleta de ejemplos.
</p><p>Esta capacidad es similar a las características que presentan lenguajes tales como Perl o Python.
</p>
<h3 name="Ejemplos"> Ejemplos </h3>
<p>La asignación desestructurada se explica mejor con ejemplos por lo que aquí se muestran un par de ellos con fines didáctico.
</p>
<div class="note"><b>Nota:</b> Si tienes ejemplos más interesantes con formas de utilizar la asignación desestructurada, por favor, anímate a añadirlos a esta sección.</div>
<h4 name="Intercambiando_valores"> Intercambiando valores </h4>
<p>Se puede usar la asignación desestructurada para, por ejemplo, intercambiar valores:
</p>
<pre>var a = 1;
var b = 3;

[a, b] = [b, a];
</pre>
<p>Tras ejecutar este código, <var>b</var> valdrá 1 y <var>a</var> valdrá 3.
</p><p>O para rotar valores: (formato de código pobre)
</p>
<pre>&lt;body bgcolor = "black"&gt;

&lt;script type="application/javascript;version=1.7"/&gt;

var a = 'o';
var b = "&lt;font color = 'green'&gt;o&lt;/font&gt;";
var c = 'o';
var d = 'o';
var e = 'o';
var f = "&lt;font color = 'blue'&gt;o&lt;/font&gt;";
var g = 'o';
var h = 'o';

for (lp=0;lp&lt;40;lp++)
	{[a, b, c, d, e, f, g, h] = [b, c, d, e, f, g, h, a];
	 document.write(a+''+b+''+c+''+d+''+e+''+f+''+g+''+h+''+"&lt;br /&gt;");}
&lt;/script&gt;
</pre>
<p>Después de ejecutar este código, se mostrará un espectáculo de colores gracias a la rotación de las variables.
</p>
<h4 name="Devolviendo_m.C3.BAltiples_valores"> Devolviendo múltiples valores </h4>
<p>Gracias a la asignación desestructurada, las funciones pueden devolver múltiples valores. Dado que las funciones siempre han podido devolver funciones, ésto proporciona una vuelta de tuerca a la flexibilidad.
</p>
<pre>function f() {
  return [1, 2];
}
</pre>
<p>Como se puede observar, los resultados se devuelven usando una notación parecida a la utilizada con los arrays, con los valores que se quieren devolver encerrados entre corchetes. Así, se puede devolver un número cualquiera de resultados. En el siguiente ejemplo, <code>f()</code> devuelve el valor <code>{{mediawiki.external('1, 2')}}</code>.
</p>
<pre>var a, b;
[a, b] = f();
document.write ("A es " + a + " B es " + b + "&lt;BR&gt;\n");
</pre>
<p>El comando <code>{{mediawiki.external('a, b')}} = f()</code> asigna el resultado de la función a las variables ubicadas por orden entre corchetes: <var>a</var> queda establecido a 1 y <var>b</var> a 2.
</p><p>También se pueden obtener los valores devueltos como un array:
</p>
<pre>var a = f();
document.write ("A es " + a);
</pre>
<p>En este caso, <var>a</var> será un array que contendrá los valores 1 y 2.
</p>
<h4 name="Ignorar_ciertos_valores_devueltos"> Ignorar ciertos valores devueltos </h4>
<p>Se pueden ignorar algunos valores devueltos en los que no se esté interesado:
</p>
<pre>function f() {
  return [1, 2, 3];
}

var [a, , b] = f();
document.write ("A is " + a + " B is " + b + "&lt;BR&gt;\n");
</pre>
<p>Tras ejecutar este código, <var>a</var> valdrá 1 y <var>b</var>, 3.  El valor 2 es ignorado.
</p>
<h4 name="Iteraci.C3.B3n_sobre_objetos"> Iteración sobre objetos </h4>
<p>Se puede usar asignación desestructurada para recuperar datos de un objeto.
</p>
<pre>var obj = { nombre: "Bob", puntos: 1.5, edad: 35 };

for (let[nombre, valor] in obj) {
  document.write ("Nombre: " + nombre + ", Valor: " + valor + "&lt;BR&gt;\n");
}
</pre>
<p>Este bucle recorre todos los pares clave/valor del objeto <var>obj</var> y muestra sus nombres y valores. En este caso, la salida será algo así:
</p>
<pre>Nombre: nombre, Valor: Bob
Nombre: puntos, Valor: 1.5
Nombre: edad, Valor: 35
</pre>
<h4 name="Iteraci.C3.B3n_sobre_valores_en_arrays_de_objetos"> Iteración sobre valores en arrays de objetos </h4>
<p>Se puede iterar un array de objetos, accediendo a los campos que interesen de cada objeto.
</p>
<pre>var personas  = [
  {
    nombre: "Mike Smith",
    familia: {
      madre: "Jane Smith",
      padre: "Harry Smith",
      hermana: "Samantha Smith"
    },
    edad: 35
  },
  {
    nombre: "Tom Jones",
    familia: {
      madre: "Norah Jones",
      padre: "Richard Jones",
      hermano: "Howard Jones"
    },
    edad: 25
  }
];

for each (let {nombre: n, familia: { padre: f } } in personas) {
  document.write ("Nombre: " + n + ", Padre: " + f + "&lt;BR&gt;\n");
}
</pre>
<p>Esto copia el valor del campo <var>nombre</var> a <var>n</var> y el del campo <var>familia.padre</var> a <var>f</var> y luego los muestra por pantalla. Esto se hace para cada objeto del array <var>personas</var>. La salida será algo así:
</p>
<pre>Nombre: Mike Smith, Padre: Harry Smith
Nombre: Tom Jones, Padre: Richard Jones
</pre>
{{ wiki.languages( { "en": "en/New_in_JavaScript_1.7", "fr": "fr/Nouveaut\u00e9s_dans_JavaScript_1.7", "pl": "pl/Nowo\u015bci_w_JavaScript_1.7" } ) }}
Revertir a esta revisión