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

HTTP2 para programadores. Enviar mensajes del servidor al cliente con Server Sent Event (sin WebSockets)

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

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

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

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

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.