Seleccionar página

Las propiedades de los objetos en Javascript son propiedades enumerables y no enumerables, es decir, son enumerables si son obtenidas por for in o Object.keys(objeto), son no enumerables si no son obtenidas por estas instrucciones y funciones, aunque estén presentes en el objeto.

Por ejemplo, las propiedades de los objetos nativos de Javascript están definidas como no enumerables, por lo que cuando utilizamos bucles for in sobre estos objetos no se obtiene estas propiedades, aunque estén presentes dentro de la cadena de prototipos y sean propiedades heredadas (ver Propiedades propias y heredadas de los objetos).

Por ello, para comprobar si una propiedad está presente en un objeto no podremos utilizar simplemente for in, ni tampoco vamos a poder utilizar Object.keys(objecto), ya que si la propiedad es no enumerable estará presente, aunque no la obtengamos de esta forma.

Sí podemos utilizar el operador in. No se suele ver mucho el uso de este operador y por el contrario se encuentran formas mucho más complejas o, incluso erróneas, de comprobar la existencia de una propiedad en un objeto, por ejemplo, comprobamos si la propiedad es verdadera, ya que puede esta contener false o null.

var objeto = {
    ok: false
};

// Forma correcta de comprobar la existencia de una propiedad
if ('ok' in objeto) {
    console.log("'ok' in objeto");          // Se muestra
}
if ('toString' in objeto) {
    console.log("'toString' in objeto");    // Se muestra
}

// Forma inconsistente de comprobar la existencia de una propiedad
if (objeto.ok) {
    console.log("objeto.ok");               // No se muestra y debería
}
if (objeto.toString) {
    console.log("objeto.toString");         // Se muestra
}

// Forma correcta y habitual de comprobar la existencia de una propiedad
if (typeof objeto.ok !== 'undefined') {
    console.log("typeof objeto.ok !== 'undefined'");        // Se muestra
}
if (typeof objeto.toString !== 'undefined') {
    console.log("typeof objeto.toString !== 'undefined'");  // Se muestra
}

// Forma compleja de comprobar la existencia de una propiedad
// que sólo funciona para propiedades propias
if (Object.keys(objeto).indexOf('ok') !== -1) {
    console.log("Object.keys(objeto).indexOf('ok') !== -1");        // Se muestra
}
if (Object.keys(objeto).indexOf('toString') !== -1) {
    console.log("Object.keys(objeto).indexOf('toString') !== -1");  // No se muestra
}

Por otra parte, para saber si una propiedad es enumerable o no podemos utilizar dos útiles métodos. El primero es objeto.propertyIsEnumerable("propiedad"). Este método devuelve true si la propiedad es enumerable y false si no lo es.

var objeto = {
    ok: false
};

if (objeto.propertyIsEnumerable('ok')) {
    console.log("'ok' es enumerable");          // Se muestra
} else {
    console.log("'ok' no es enumerable");
}

if (objeto.propertyIsEnumerable('toString')) {
    console.log("'toString' es enumerable");
} else {
    console.log("'toString' no es enumerable"); // Se muestra
}

Otra forma, más completa, de comprobar las características de las propiedades es utilizar Object.getOwnPropertyDescriptor(objeto). Este método sólo funciona con propiedades propias y no funciona con propiedades heredadas de la cadena de prototipos. Devuelve un objeto con información completa sobre la propiedad.

var objeto = {
    ok: false
};
console.log(Object.getOwnPropertyDescriptor(objeto, 'ok'));
// Mostrará algo parecido a esto
// { value: false,
//   writable: true,
//   enumerable: true,
//   configurable: true }

console.log(Object.getOwnPropertyDescriptor(Object.prototype, 'toString'));
// Mostrará algo parecido a esto
// { value: [Function: toString],
//   writable: true,
//   enumerable: false,
//   configurable: true }

Nosotros podemos definir propiedades no enumerables sobre cualquier objeto a través de descriptores donde se definen las propiedades y sus características. Para ellos podemos utilizar:

  • Object.create(prototipo, descriptores)
  • Object.defineProperty(objeto, "propiedad", descriptor)
  • Object.defineProperties(objeto, descriptores)

Básicamente lo que se utiliza en estos métodos es un descriptor, es decir, una estructura similar que la que devuelve Object.getOwnPropertyDescriptor(objeto,"propiedad") donde se describen las características de las propiedades.

// Se crea un objeto con un descriptor de sus propiedadades
var objeto = Object.create(Object, {
    ok: {
        value: false,
        enumerable: false
    },
    num: {
        value: 10,
        enumerable: true
    }
});

// Se añade una propiedad no enumerable a todos los objetos
Object.defineProperty(objeto.prototype, 'debug',
    {   value: function() {
                //...
            },
        enumerable: false
    }
);

// Se comprueban las propiedades enumerables (propias y heredadas)
for (var prop in objeto) {
    console.log(prop);  // num
}

// Se comprueban las propiedades enumerables (propias)
Object.keys(objeto).forEach(function(prop) {
    console.log(prop);  // num
});

// Se comprueba que existe la propiedad 'debug'
if ('debug' in objeto) {
    console.log("'debug' in objeto");   // Se muestra
}

Como hemos venido explicando, Object.keys(objeto) y for in sólo muestran propiedades enumerables. En ocasiones vamos a necesitar conocer los nombres de todas las propiedades, indiferentemente de si son enumerables o no, para ello se debe utilizar Object.getOwnPropertyNames(objeto). Con este método vamos a obtener todos las propiedades propias (no las heredadas) de un objeto.

// Se crea un objeto con un descriptor de sus propiedadades
var objeto = Object.create(Object, {
    ok: {
        value: false,
        enumerable: false
    },
    num: {
        value: 10,
        enumerable: true
    }
});

// Se añade una propiedad no enumerable a todos los objetos
Object.defineProperty(objeto.prototype, 'debug',
    {   value: function() {
                //...
            },
        enumerable: false
    }
);

// Se comprueban las propiedades enumerables (propias)
Object.getOwnPropertyNames(objeto).forEach(function(prop) {
    console.log(prop);  // ok, num
});

Quizás pueda parecer que estamos complicando mucho la creación de objetos y que en la mayoría de las ocasiones no será necesario trabajar a este nivel de configuración de las propiedades de un objeto, pero lo cierto es que definir una propiedad como no enumerable puede tener bastantes ventajas.

Si reescribimos una propiedad como toString() está pasa a ser enumerable si no la definimos por medio de Object.defineProperty(). También es útil para añadir propiedades a un objeto que ya estamos utilizando y no afectar al comportamiento previsto de los bucles for in o las llamadas a Object.keys(objeto) que no esperan recibir estas nuevas propiedades.

Javascript ofrece mucha más flexibilidad a la hora de trabajar con objetos y propiedades de la que se suele utilizar. Conocer y aprovechar estas características nos permite desarrollar programas más robustos y capaces de adaptarse a contextos de uso diferentes sin que se vea afectado su funcionamiento.

Novedades

customElements a fondo

Vamos a dar repaso general a customElements y todos sus métodos. Esta es una pieza clave para la creación de Custom Tag, uno de los pilares de los Web Components. Hemos intentado empezar por lo más básico e ir avanzando hasta describir algunos de sus comportamientos más complejos, además de describir algunas de las características más importantes de los Web Components.

Uso de jsRPC en una aplicación de ejemplo

Para poder comprender mejor cómo podemos utilizar la librería jsRPC hemos creado una aplicación de ejemplo en la que hemos utilizado el modelo RPC para que el front invoque funciones del servidor y para que los diferentes microservicios invoquen de forma remota funciones entre ellos.

Un completo sistema RPC en Javascript con sólo 100 líneas

La aparición de gRPC de Google ha hecho que vuelva a ponerse de moda los sistemas de Remote Procedure Calls. La mayoría de las implementaciones de RPC se han ajustado muy poco a las características idiomáticas de Javascript. Con jsRPC mostramos cómo desarrollar un completo sistema RPC utilizando las características de Javascript.

Usar correctamente el método sort()

En general no se hace un uso habitual del método .sort() de los Array y muchas ocasiones se desconoce cómo hacer funcionar este método de forma correcta. En este artículo os contaremos cómo funciona y cómo sacar partido a sus características.

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.

Operadores de bits usados con asiduidad

Cada día más a menudo podemos encontrar operadores binarios 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 en detalle.

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.