Seleccionar página

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 segundo
  • test.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

Debate: Tecnologías de Front Web [vídeo]

Desde las principales comunidades de desarrollo de tecnologías de front (Madrid JS, Polymer Madrid, Angular Madrid y VueJS Madrid) se ha organizado este debate que pretende ser un ejercicio de sentido común en relación a las tecnologías de front actuales centradas en componentes.

El microservicio más grande del mundo [vídeo]

en esta interesante charla, Felipe Polo nos cuenta cómo un servicio puede crecer manteniendo su status “micro”, manteniendo su coherencia y orden, para resolver un problema de migración desde una aplicación monolítica hasta un sistema basado en microservicios.

Web Assembly workshop by Dan Callahan [video]

Este taller (en inglés) nos adentra en WebAssembly, cómo funciona y cuándo debe usarlo. También se describe cómo usar las herramientas de creación de perfiles. Esta nueva herramienta de bajo nivel y alto rendimiento está emergiendo con fuerza y debes conocerla.

breves

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.

Cómo diferenciar arrow function de function

En un reciente artículo Javier Vélez Reyes hace patente las principales diferencias entre las funciones tradicionales y las funciones flecha, ya que ambos modelos no son equivalentes e intercambiables. Veamos cómo es posible saber si una función ha sido construida por medio de la instrucción function o como una arrow function.

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.