Wextensible

Un sitio personal para aprender desarrollo web

Objeto de tipos para verificar argumentos de una función

JavaScript es débilmente tipado. Esto puede ser una desventaja cuando ejecutamos una función, pues no podemos asegurar que los tipos de los valores que se reciban sean los esperados. Se soluciona incorporando controles con typeof para ver si el argumento es del tipo esperado. No deja de ser un trabajo y código adicional que tenemos que incorporar en cada función y para cada paramétro que queramos verificar. Es una pena que JavaScript no tenga algo como si tiene TypeScript, donde la declaración function fun(a: number, b: string) obliga a que los argumentos tengan que ser de esos tipos.

Pero con ES6 y los parámetros por defecto o predeterminados podemos construirnos una función verificadora que lleve a cabo esa comprobación de forma automática. Para ello usaremos el código de la función obtenido con fun.toString(), parseando una cabecera como fun(a="", b=0) para deducir que los parámetros son de tipos string y number respectivamente, lo que se deduce de los tipos de los valores predeterminados. Con ello construiremos un objeto de tipos como el de la imagen, que nos servirá para verificar los tipos de los argumentos.

El método keys() recupera las claves de un objeto

El término iterar debemos entenderlo como repetir un mismo proceso sobre los propiedades de un objeto. Podemos, por ejemplo, recorrer todas las propiedades buscando áquellas cuyos valores sean tipos string y hacer algo con esos valores. Por definición los objetos creados directamente de Object no son iterables, pero otros como los Array si lo son, pues implementan un método Symbol.iterator(). Para iterar por un objeto hemos de recurrir a sus propios métodos, como Object.keys() que recupera un Array con las claves del objeto. Como todos los objetos derivan de Object estos métodos también se pueden aplicar a ellos, junto a la posibilidad de que implementen también el método Symbol.iterator().

Todos los objetos de JavaScript se constituyen con propiedades como parejas clave-valor

Las frases JavaScript está basado en objetos, Los objetos se relacionan a través de los prototipos y Los objetos contienen propiedades clave-valor podrían servir para identificar este lenguaje de programación. La última podría parecer innecesaria, pero describe la estructura de los objetos en JavaScript, dado que una propiedad es una entidad como una pareja clave-valor.

En este tema agrupamos todos los métodos que nos permiten crear y modificar propiedades como defineProperty(). Otros métodos como freeze() y seal() nos permitirán congelar y sellar respectivamente un objeto.

Todos los objetos de JavaScript tiene un __proto__ (prototipo)

Entender los prototipos de los objetos es imprescindible para manejarse bien con JavaScript. Por eso hemos agrupado en este tema todos los métodos que tienen que ver con los prototipos.

Podemos llegar a JavaScript desde otros lenguajes de programación que usan Programación orientada a objetos (POO). En ese caso podríamos decirnos lo siguiente: JavaScript, otro lenguaje basado en objetos, si conozco POO tendré bastante ventaja. Pero es una gran equivocación pensar así. JavaScript está basado en objetos, pero la relación entre ellos se produce a través de los prototipos. Y esto nada tiene que ver con POO, aunque la relación prototípica pueda simular bastante bien la POO.

El método toLocaleString() nos permite dar formato local a cadenas.

En Object hay algunos métodos básicos cuyo propósito es que puedan ser sobrescritos en las instancias, especialmente en los built-in como Array, Number o Date. Son los métodos del prototipo toString(), toLocaleString() y valueOf(). Con este último haremos un ejemplo de tipo de números romanos, evidenciándose para que sirve ese método. Con toLocaleString() podemos convertir a formato local tanto números como fechas.

Otro método que veremos es Object.is() que complementa las comparaciones de igualdad estricta === y con coerción ==. Explicaremos porque se aconseja siempre usar la comparación estricta.

Los objetos en JavaScript se relacionan a través de los prototipos

Conocer JavaScript pasa necesariamente por conocer los objetos y como se relacionan por medio de prototipos. La frase en JavaScript todo son objetos trata de sintetizar el hecho de que JavaScript es un lenguaje de objetos basado en prototipos, donde los objetos heredan de otros objetos y en última instancia del prototipo de Object (Object {}).

En este tema y los siguientes haré un repaso general de Object y sus métodos. Especialmente con la puesta al día de lo nuevo de ES6 relacionado con los objetos.

Trozo de código de XHR (AJAX)

Se dice que JavaScript está conducido por eventos. Por ejemplo, un evento click sobre un botón, los eventos del reloj del sistema que podemos usar con setTimeout() o peticiones asíncronas con XMLHttpRequest (AJAX, XHR) nos permitirán simular tareas complejas en JavaScript. Los nuevos generadores y promesas de ES6 resultarán muy útiles para implementar esas tareas, obteniéndose un código más claro y un control de errores más potente.

Esquema de multitarea con tres procesos A, B y C

La ejecución en multitarea significa que sólo tenemos un procesador y podemos llevar a cabo la ejecución de múltiples procesos compartiendo el tiempo de uso de ese procesador. Supongamos que tenemos los procesos A, B y C. Ejecutamos A durante un tiempo, lo paramos y ejecutamos B durante otro tiempo y así hasta que todos los procesos finalicen su tarea respectiva. Aparentará que los tres procesos se están ejecutando a la vez, pero realmente estaremos realizando alternativamente un trozo de ejecución de cada uno. Los generadores de ES6 nos facilitarán implementar algo parecido a multitarea en JavaScript.

Generadores en ES6

Código de un generador en ES6

Un generador es una función cuya ejecución puede ser pausada en un momento dado y continuada en otro posterior. En la pausa, que se produce cuando se ejecuta una expresión con yield, la función conserva su estado de variables. La pausa es, por tanto, ejecutada desde la propia función generadora con yield, mientras que la reanudación sólo puede llevarse a cabo externamente. Este comportamiento tiene tiene muchas utilidades, como la simulación de multitarea o gestionar mejor las tareas asíncronas combinando generadores y Promesas.

Iterables en ES6

Symbol.iterator en JavaScript

Los objetos iterables implementan el método Symbol.iterator. La ejecución de este método devuelve un objeto iterador que nos servirá para iterar por el objeto. En el objeto iterador siempre habrá un método next() que nos devuelve el siguiente elemento de la iteración. Los bucles for-of, el desestructurado de datos o el operador de propagación de Array se sustentan en que el objeto sobre el que se aplican sea un iterable.

Algunos objetos built-in como Array, Set, Map o arguments poseen intrínsicamente un método iterador. Además en este tema exponemos como podemos implementar un iterador particular para cualquier objeto, con lo que conoceremos cual es la finalidad de la iterabilidad y como puede ayudarnos a crear funciones iterables.

El método join() transforma un Array en un String

Los métodos de este tema transforman un Array en un valor simple devolviéndolo y no modificando el Array sobre el que actuan. Incluye los métodos antiguos join(), toString() y toLocaleString() que devuelven un String con los elementos del Array.

Más interesante son los métodos reduce() y reduceRight(). Ambos funcionan igual, sólo que el primero itera de izquierda a derecha en los índices del Array y el segundo lo hace al revés. Usa un callback para ir acumulando el resultado, por lo que es un método que tiene un gran número de aplicaciones. Como una implementación del algoritmo de exponenciación rápida, que también podemos hacer con el método reduce().

El método indexOf(valor) nos devuelve el índice

Los métodos para realizar búsquedas en un Array se pueden agrupar en tres clases. Están los que devuelven un valor booleano según encuentren o no lo que buscan, como every(), some() e includes(). Por otro lado están los que devuelven el índice del valor a buscar, con los métodos findIndex(), indexOf() y lastIndexOf().

Por último el método find() devuelve el valor que se está buscando según una condición en el callback. También funcionan con un callback los métodos some(), find() y findIndex(). El método includes() es de EcmaScript 2016 (ES7), pero ya los navegadores actuales más usados lo soportan. Haremos un ejemplo para obtener el valor de un grupo de botones de radio (<input type="radio">) usando, entre varias técnicas, el método find().

El método concat() crea un nuevo Array

Los métodos concat(), map(), slice() y filter() devuelven un nuevo Array, no modificando el Array sobre el que estén actuando. Con map() iteramos por el Array devolviendo otro Array con el mismo número de elementos, donde sus valores se establecen en una función callback. Los otros métodos, o map() cuando devuelve los valores, realizan una copia superficial del valor.

Con el método slice() haremos un ejemplo de búsqueda binaria, un algoritmo que reduce el coste de buscar un valor en un Array con un orden logarítmico.

Método para iterar por un Array

Iterar por un Array es acceder a sus elementos de forma secuencial. Los métodos key(), values() y entries() devuelven un objeto iterador que nos permitirá esa acción. El método forEach() funciona con un callback con iterando por el Array sin propósito específico.

Métodos push, pop, shift y unshift de un Array de JavaScript

Los métodos básicos para modificar un Array son pop(), push(), shift() y unshift(). Éstos agregan o eliminan elementos por la cabeza o la cola del Array. Son ideales para implementar una pila o una cola. Como ejemplo de pila implementaremos un conversor de expresiones aritméticas con notación infija a notación polaca inversa (RPN), tras lo que podremos ejecutar las expresiones con suma facilidad. Tambien hay un ejemplo de una cola para descargar archivos de imagen asíncronamente.

Otros métodos que modifican el Array sobre el que se aplican son copyWithin(), fill(), reverse(), splice() y sort(). Con el último haremos un ejemplo para ordenar una tabla por columnas.

El constructor Array de JavaScript

El constructor de Array ahora tiene dos nuevos métodos genéricos: Array.of() y Array.from(). Éste último nos permite crear un nuevo Array a partir de un iterable o de un array-like, objetos que se parecen a un array. Por otro lado comentaremos el método Array.isArray() para saber si un objeto es un Array.

A veces uno da por hecho cosas que merece la pena volver a comprobar, debido a que los navegadores son cada vez más eficientes o quizás lo que aprendimos no era del todo correcto. Como ejemplo comprobaremos si es más eficiente declarar un Array con notación literal o usando el constructor.


...Ver más en el histórico