En general se considera que la utilización de operadores de bits (u operadores binarios) no es una buena idea en Javascript. Seguramente esta opinión viene dada por el posible error en el uso de &
cuando queríamos escribir &&
o |
cuando realmene queríamos utilizar ||
.
También es posible que el uso de operadores de bits no sea muy necesario en los contextos más habituales de uso de Javascript, pero lo cierto es que cada día más a menudo podemos encontrar estos operadores de bits utilizados como formas abreviadas de algunas operaciones que de otra forma sería algo menos compactas y, quizás, más comprensibles. Veamos algunos casos:
0 | exp
|
es el operador OR binario, en este caso, con el valor 0
se suele utilizar para obtener la parte entera de un número, eliminando cualquier decimal que tenga.
En general podremos ver este tipo de operación en códigos como este:
var alet = 0 | Math.random() * 100;
En la variable alet
se almacenará un entero entre 0 y 100, ya que al multiplicar Math.random()
por 100
obtendremos un valor entre 0.0000
y 100.9999
y con 0 |
se obtendrá sólo la parte entera de este valor.
No es que sea mucho más compleja la expresión alternativa escrita de forma tradicional:
var alet = parseInt(Math.random() * 100)
La versión que utiliza el operador binario es algo más eficiente en término de velocidad. Lo podemos comprobar utilizando BenchmarkJS y esta sencilla prueba:
var benchmark = require('benchmarkjs'); benchmark('0 | Math.random() * 100', function() { return 0 | Math.random() * 100; }); benchmark('parseInt(Math.random() * 100)', function() { return parseInt(Math.random() * 100); }); console.log(benchmark.results);
En mi máquina obtengo 144.600.896 veces por segundo para 0 | Math.random() * 100
y 55.945.195 veces por segundo (61.31% más lento) para parseInt(Math.random() * 100)
. No obstante, estamos hablando de millones de ejecuciones por segundo, por lo que en la mayoría de los casos estamos hablando de una nano-optimización que pasará completamente desapercibida en el rendimiento general de nuestro programa.
exp >>> 0
Este operador desplaza el primer operando el número especificado de bits a la derecha y el exceso de bits desplazados hacia la derecha se descartan. El bit de signo se convierte en 0, por lo que el resultado es siempre positivo. Además, en el caso de que la expresión no sea numérica o no pueda convertirse a un número, devolverá 0.
El uso de este operador se ha extendido para un caso muy particular: los polyfill de métodos que utilizan matrices, concretamente a la hora de obtener su tamaño con length
. Normalmente veremos algo de este tipo:
var len = this.length >>> 0;
Aquí se está utilizando una característica de este operador, ya que si this.length
no existe o no es convertible a un número, entonces se devolverá 0
. Es posible utilizar este operador ya que length
en ningún caso será un numero negativo, ya que el operador >>>
daría un resultado no deseado en ese caso.
El código tradicional tampoco es mucho más complejo:
var len = this.length ? this.length : 0;
o todavía más sencillo:
var len = this.length || 0;
Es cierto que si length
por un extraño motivo tienen una cadena, este segundo método no funcionaría y el anterior sí, pero en general se puede considerar un código más comprensible.
En este caso no existe a penas diferencia de rendimiento. Ejecutamos estos test con BenchmarkJS:
var benchmark = require('benchmarkjs'); var test = [1, 2, 3]; benchmark('test.length >>> 0', function() { return test.length >>> 0; }); benchmark('test.length ? 0 : test.length', function() { return test.length ? 0 : this.length; }); console.log(benchmark.results);
test.length >>> 0
– 1.707.025.457 operaciones por segundotest.length ? 0 : test.length
– 1.301.322.219 operaciones por segundo (23.77% más lento)
var benchmark = require('benchmarkjs'); var test = {}; benchmark('test.length >>> 0', function() { return test.length >>> 0; }); benchmark('test.length ? test.length : 0', function() { return test.length ? test.length : 0; }); console.log(benchmark.results);
test.length >>> 0
– 1.759.007.568 operaciones por segundo (0,65% más lento)test.length ? test.length : 0
– 1.770.602.872 operaciones por segundo
Como podemos observar estamos tratando de miles de millones de operaciones por segundo y de diferencias bastante pequeñas como para considerar la utilización de >>>
como una optimización.
¿Utilizamos o no este tipo de expresiones?
En general este tipo de operaciones hacen el código un poco más compacto, pero también lo pueden hacer menos comprensible y por lo tanto menos mantenible. En algunos casos es posible que supongan una pequeña mejora de rendimiento, pero en general hay que tener cuidado con ellos. No es absolutamente necesario evitarlos, sobre todo si sabemos que el resto de nuestro equipo van a comprenderlos con rapidez y no van a dudar de su significado y comportamiento, pero creemos que ocasiones su uso es propio de un estilo de programación obtuso y poco comprensible.
Novedades
HTTP2 para programadores. Enviar mensajes del servidor al cliente con Server Sent Event (sin WebSockets)
En esta charla, organizada por MadridJS, Pablo Almunia nos muestra cómo la mayoría de nosotros cuando oímos hablar por primera vez de HTTP2 nos ilusionamos con las posibilidades que presumiblemente se abrían para el desarrollo de soluciones web avanzadas y cómo muchos nos sentimos defraudados con lo que realmente se podía implementar.
En esta charla podemos ver cómo funciona el HTTP2, que debemos tener en cuenta en el servidor para hace uso de este protocolo y, sobre todo, cómo podemos enviar información desde el servidor al cliente de forma efectiva y fácil. Veremos con detenimiento cómo por medio de los Server-Sent Events (SSE) podemos recibir en el cliente datos enviados desde el servidor sin utilizar websocket, simplificando enormemente la construcción de aplicaciones con comunicación bidireccional.
Observables en Javascript con Proxies
En esta charla, organizada por MadridJS, Pablo Almunia nos habla de la observación reactiva de objetos en Javascript por medio de Proxy. Se describe paso a paso cómo funcionan los Proxies y en que casos pueden ser nuestro mejor aliado. Veremos que no hay que tenerles miedo, son bastante sencillos de utilizar, y nos ofrecen una gran abanico de posibilidades.
Aplicaciones JAMStack, SEO friendly y escalables con NextJS
En esta charla de Madrid JS, Rafael Ventura nos describe las funcionalidades clave de NextJS, nos muestra en vivo cómo desarrollar una completa aplicación JAMStack con Server Side Rendering (SSR) y Static Site Generation (SSG) y termina mostrando como publicar esta aplicación en Vercel.
Stencil JS: mejora el Time To Market de tu producto, por Rubén Aguilera
En esta charla Rubén Aguilera nos cuenta los problemas que tienen muchas empresas a la hora de sacar productos accesibles, vistosos y usables en el Time To Market que requiere Negocio y cómo podemos minimizar este tiempo gracias al DevUI con StencilJS para adecuar una aplicación de Angular a las exigencias del mercado en tiempo record.
breves
Javascript: 25 aniversario
25 años con Javascript han dado para mucho. Pero todavía queda mucho para este lenguaje de programación.
Descrubir algunas características de console
En el día a día nos encontramos muy a menudo utilizando console. Es una navaja multiusos que nos facilita la vida a la hora de depurar nuestro código. La mayoría de nosotros ha utilizado console.log(), pero tiene otras muchas funcionalidades.
Matrices dispersas o sparse arrays en JS
Una característica que puede producir algunos problemas, si no lo tenemos en cuenta, es la posibilidad de tener matrices con huecos, es decir, con algunos de sus elementos sin definir. Es lo que se suele denominar una matriz dispersa o sparse array. Veamos cómo trabajar con esta características de las matrices.
Obtener todas las propiedades de un objeto
¿Cómo podemos obtener absolutamente todas las propiedades de un objeto? No disponemos de un método nativo para este propósito, pero en unas pocas lineas podemos construir una función para nuestro propósito.