Seleccionar página
Cuando se conocen las clases en ECMAScript 2015 (ES6) se echan en falta algunos mecanismos para definir propiedades o métodos ocultos, pudiendo de esta forma proteger estos miembros de miradas curiosas. Es algo común en muchos lenguajes con orientación a objetos y parecía una carencia importante en Javascript.

Rápidamente se plantearon varias alternativas para la encapsulación en las clases de ES6, una de ellas está basada en el uso de Symbol, ya que un objeto puede contener propiedades cuya clave es un símbolo en vez de una cadena de texto. La idea es que, si sólo nosotros tenemos acceso al símbolo con el que se ha creado el miembro, sólo nosotros podremos acceder al miembro del objeto.

Más o menos, esto es un ejemplo de lo que se plantea el uso de Symbol para dar protección a ciertos miembros del objeto:

const SECRET = Symbol( 'SECRET' );

class A {
  constructor ( data ) {
    this[ SECRET ] = data;
  }
}

const a = new A( 'no se lo digas a nadie' );

No sólo se puede utilizar para propiedades, también podemos definir métodos por medio de Symbol y algo de destructuring, por ejemplo:

const HIDE = Symbol( 'HIDE' );

class B {
  [ HIDE ] () {
    return 'oculto';
  }
}

const b = new B( );
console.log( b[ HIDE ]() );

Sólo si se tiene acceso a las constantes con los símbolos se puede acceder a los miembros creados con SECRET y HIDE. Si mantenemos estas constantes como locales al módulo o dentro de una closure, todo parece bastante prometedor.

Rápidamente vimos que los depuradores de los navegadores y de entornos integrados mostraban los miembros definidos con Symbol(). Fue una decepción, pero no era un drama, al fin y al cabo, desde un entorno de depuración es posible detener la ejecución en cualquier punto y comprobar el contenido de una variable local, por lo que parece imposible protegerse de este tipo de herramientas.

Symbol en el depurador

Llegamos a este punto, lo que no nos habíamos dado cuenta es que hay varias formas de obtener desde un programa el Symbol con el que se ha definido el miembro del objeto y por lo tanto, acceder sin problemas y sin limitaciones a estas propiedades que se intentó ocultar, pero que son perfectamente visibles con un poco de esfuerzo.

Un simple código como nos permite obtener el contenido de todas las propiedades, incluido las definidas con símbolos.

console.log( Object.getOwnPropertyDescriptors(a) )

Lo que ya fue el colmo de los males es descubrir que Object.getOwnPropertySymbols() o Reflect.ownKeys() devuelven una matriz que incluyen los símbolos utilizados en el objeto y que permite a un programa acceder sin problemas a estas propiedades.

const SECRET = Symbol( 'SECRET' );

class A {
  constructor ( data ) {
    this[ SECRET ] = data;
  }
}

const a = new A( 'no se lo digas a nadie' );

const MySYMBOL = Object.getOwnPropertySymbols( a )[ 0 ];
a[MySYMBOL] = 'todo el mundo lo sabe';

Es cierto que los símbolos son ignorados en muchas ocasiones, por ejemplo, por los bucles for...in y por métodos habituales para obtener los nombres de las propiedades, Object.keys() y Object.getOwnPropertyNames(), por lo que las propiedades creados con ellos no son tan visibles como el resto.

En un futuro próximo parece que el estándar de Javascript va a incluir una forma de definir miembros privados (ver la propuesta de Private instance methods and accessors). Esta propuesta está en estado 3 (de un total de 4) y se espera que próximamente sea incluida de forma efectiva en los motores de Javascript.

Por lo tanto, los Symbol tienen muchas utilidades, pero no consiguen una ocultación efectiva de los miembros de un objeto. Es verdad que las propiedades creadas con Symbol son más complicadas de acceder, pero desde luego no son privadas.

Novedades

Limitar el tamaño de un Map

Limitar el tamaño de un objeto Map no parece una idea muy razonable, pero cuando tu programa se ejecuta sin interrupción durante días, semanas, meses e inclusos años, es muy importante controlar el tamaño de la memoria utilizada para evitar problemas inesperados. Una simple función memoize puede llegar a almacenar mucha más información de la que puedes pensar. Aquí te contamos como limitar el tamaño de un objeto Map para estas situaciones.

Cómo conseguir un objeto Map ordenado

Mantener un objeto Map con su contenido ordenado no es algo tan sencillo como parece. Por defecto, Map guarda los datos en el mismo orden en el que han sido creados en el objeto. Para conseguir que el contenido se muestre ordenado tendremos que explorar varias interesantes alternativas que nos descubrirán algunas de características interesantes de estas estructuras de datos.

¿Es una función nativa de Javascript?

Comprobar si una determinada función es una función nativa de Javascript o es una función escrita en código es algo más complicado de lo que pueda parecer a primera vista. No hay grandes diferencias entre una función nativa y una escrita por nosotros, por lo que tenemos que buscar mecanismos algo indirectos para poder diferenciarlas.