Apply your JS skills to key Mozilla projects as an MDN Fellow! http://mzl.la/MDNFellowship

mozilla
Los resultados de tu búsqueda

    Novedades en JavaScript 1.7

    JavaScript 1.7 es una actualización del lenguaje que le añade algunas nuevas características, como generadores, iteradores, comprensión 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 compilaciones actuales.

    Los ejemplos de código incluidos en este artículo pueden ser probados en la consola JavaScript. Si quieres aprender a construir o utilizar esta consola, lee Introducción al shell de 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, utiliza:

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

    Cuando se utilice el shell de JavaScript, debes 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

    Considera este algoritmo iterativo que obtiene los números 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 código 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 para proveer nuevas y mejores formas de hacer esto. Veamos cómo 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 que contiene la palabra clave yield es un generador. Cuando es llamada, sus parámetros formales son instanciados a los argumentos actuales, pero su cuerpo no es realmente evaluado, si no que se devuelve un generator-iterator. Cada llamada al método next() del generator-iterator realiza otro paso a través de algoritmo iterativo. El valor de cada paso es el valor especificado por la palabra clave yield. Piensa en yield como la versión generator-iterator de return que delimita la frontera entre cada iteración del algoritmo. Cada vez que se llama a next(), el código del generador continúa a partir de la sentencia que va después de yield.

    Se realiza un ciclo en el generator-iterator llamando repetidamente a su método next() hasta que se consiga la condición deseada. Con este ejemplo se pueden obtener tantos números de Fibonacci como se quiera llamando simplemente a g.next() hasta que conseguir la cantidad de números que se quiera.

    Resumiendo un generador en un punto específico

    Una vez que un generador ha sido iniciado por la invocación de su función next(), puede utilizarse send(), pasando un valor específico que será tratado como el resultado de la última producción. El generador entonces retornará el operando de la subsecuente producción.

    No se puede iniciar un generador en un punto arbitrario; deberá comenzarse con next() antes de poder enviarle [send()] un valor específico.

    Nótese: Como un punto interesante, invocando send(undefined) es equivalente a invocar next(). Sin embargo, iniciando la aparición de un nuevo generador con cualquier otro valor que no sea indefinido [undefined] cuando invoque a send() resultará como una excepción de error de tipo [TypeError exception].
    Excepciones en los generadores

    Puede forzar a un generador a lanzar una excepción mediante la invoación de su método throw(), pasándole el valor de la excepción que debe ser lanzada. Esta excepción se lanzará desde el conxtexto actual suspendido del generador, así como si el yield que está actualmente suspendido en lugar del sentencia throw valor.

    Si una producción no es encontrada durante el procesamiento de la excepción lanzada, entonces la excepción se propagará ascendentemente hasta la invocación del throw() y subsecuentemente invocará a next() que resulta en el lanzamiento de una StopIteration.

    Cerrando un generador

    Los generadores poseen el método close() que forza al generador a cerrarse por sí mismo. Los efectos de cerrar un generador son:

    1. Cualquier cláusula finally activa en la función del generador es ejecutada.
    2. Si una cláusula finally lanza cualquier excepción distinta a StopIteration, la excepción es propagada hacia el invocador del método close().
    3. El generador termina.
    Ejemplo de un Generador

    Este código maneja un generador que se producirá cada 100 lazos.

    var gen = generator();
    
    function driveGenerator() {
    	if (gen.next()) {
    		window.setTimeout(driveGenerator, 0);	
    	} else {
    		gen.close();	
    	}
    }
    
    function generator() {
    	while (i < something) {
    		/** stuff **/
    
    		++i;
    		/** 100 loops per yield **/
    		if ((i % 100) == 0) {
    			yield true;
    		} 
    	}
    
    	yield false;
    }
    

    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, <var>diez_cuadrados</var>, 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 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 <var>x</var> = x+10 e <var>y</var> = 12 es utilizado solamente en la expresión x+y

    Reglas de ámbito

    Dada la expresión let

    let (<var>decls</var>) <var style="color: blue">expr</var>
    

    existe un bloque creado implícitamente que comprende el trozo <var style="color: blue">expr</var>.

    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 <var>expr1</var>; <var style="color: blue">expr2</var>; <var style="color: blue">expr3</var>) <var style="color: blue">sentencia</var>
    

    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 let <var>expr1</var>. Esto se demuestra en el primer bucle del ejemplo.

    for (<var>expr1</var> in <var>expr2</var>) <var style="color: blue">sentencia</var>
    

    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.

    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, <var>b</var> valdrá 1 y <var>a</var> 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 [1, 2].

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

    El comando [a, b] = f() 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.

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

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

    En este caso, <var>a</var> 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, <var>a</var> valdrá 1 y <var>b</var>, 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 <var>obj</var> 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 <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í:

    Nombre: Mike Smith, Padre: Harry Smith
    Nombre: Tom Jones, Padre: Richard Jones
    

    Categorías enlaces interwikis

    Etiquetas y colaboradores del documento

    Contributors to this page: Wikier, Sheppy, Nukeador, teoli, Gbulfon, Superruzafa, Guis, Mgjbot
    Última actualización por: teoli,