Recientemente publiqué una receta “javascriptera” en la que hablaba de algunos de los usos que podemos dar al objeto Map y cuáles son sus ventajas con respecto a emplear objetos planos de Javascript.
Dado que el formato “receta” se queda corto he decidido escribir este artículo profundizando más en detalle tanto en el objeto Map de Javascript como en el objeto WeakMap, el cual tiene interesantes implicaciones a nivel de rendimiento.
¡Vamos allá!
Antes de ver las diferencias de Map con los objetos planos, veamos primero la forma de crear este tipo de objetos y emplearlos.
Lo primero de todo podemos crear un Map del siguiente modo:
const map = new Map();
const initialValues = [["key1", "value1"], ["key2", "value2"]];
const map = new Map(initialValues);
has(key) para comprobar si existe una clave.get(key) para recuperar el valor de una clave.set(key, value) para añadir una nueva clave con su valor correspondiente o sobrescribir un valor ya existente.const map = new Map([['foo', 1], ['bar', 2]]);
console.log(map.keys()); // MapIterator {"foo", "bar"}
[...map.keys()];
Y hablando de iteración, los objetos Map nos permiten iterar directamente sobre ellos bien empleando su método forEach :
map.forEach((key, value) => { /* do something */ });
for ([key, value] of map2) {
console.log(`${key} ${value}`);
}
Ahora que ya conocemos el objeto Map cabe preguntarse en qué momentos tiene sentido emplearlo en vez de los objetos planos que proporciona el lenguaje.
La primera y más es importante es la posibilidad de usar más tipos de valores para definir claves. En Javascript, cuando empleamos objetos las claves que identifican a sus propiedades tienen que ser bien strings o Symbol . En el momento en que tratemos de usar otro tipo de valores, Javascript tratará de convertirlos directamente a string:
const a = {};
const b = {[a]: 'foo'};
console.log(b); // {[object Object]: "foo"}
const a = {};
const b = true;
const fn = () => {};
const map = new Map();
map.set(a, 'foo');
map.set(b, 'bar');
map.set(fn, 'zeta');
console.log(map.get(a)); // 'foo'
console.log(map.get(b)); // 'bar'
console.log(map.get(fn)); // 'zeta'
const map = new Map([['foo', 1], ['bar', 2]]);
console.log(map.size); // 2
Finalmente, y en lo que se refiere a rendimiento, la documentación de MDN propone emplear objetos Map en vez de objetos planos cuando necesitamos realizar numerosas inserciones y borrados de claves.
Ahora que ya conocemos el objeto Map , creo que es muy interesante mencionar su versión “Weak”, es decir, un tipo de Map que establece un enlace débil con las claves empleadas de modo que pueden ser recolectadas por el “garbage collector” cuando no existen más referencias a ellas.
Javascript cuenta con un mecanismo por el cual aquellos objetos que hayamos declarado pero que tras un cierto tiempo ya no se usan en ninguna parte de nuestra aplicación (es decir, no existe ninguna referencia a ellos) , son eliminados de la memoria. Esto ayuda a controlar que no colapsemos la memoria del dispositivo que ejecuta el programa.
Un objeto WeakMap sólo puede tener objetos como claves (de modo que tenga sentido permitir que el “garbage collector” los pueda eliminar algo que no puede suceder con valores primitivos como “strings” o “numbers”).
Que tengamos que usar objetos como claves para un WeakMap tiene otra implicación: es necesario que todavía poseamos una referencia a ese objeto para poder acceder a su valor dentro del WeakMap:
const a = {};
const weakMap = new WeakMap();
weakMap.set(a, 'foo');
// if we loose a, we loose the abject to 'foo'
size a diferencia de lo que sucedía con Map .Con las “limitaciones” mencionadas anteriormente, ¿cuándo tiene sentido usar un WeakMap ? Veamos algunos casos interesantes.
1️⃣ Puesto que un valor en un WeakMap sólo existirá en tanto en cuanto el objeto que actúa como clave existe, podemos emplear un WeakMap para almacenar características extra de un objeto sin vernos obligados a modificarlo:
const person = {name: 'Gerardo'};
const weakMap = new WeakMap();
weakMap.set(person, 'some interesting property of person';
function calculateShipping(item) {
/* some expensive operations */
}
const itemInCart = {...};
const map = new WeakMap();
map.set(itemInCart, calculateShipping(itemInCart));
Como veis, tanto los Map como los WeakMap nos pueden resultar muy útiles para determinados casos. Por eso siempre os animo a no quedaros en la superficie de un lenguaje (en este caso Javascript) sino que profundicéis en todas las características que ofrece ya que pueden resultar muy muy útiles para resolver problemas que nos costaría mucho tiempo resolver si no contáramos con estas herramientas.
Gracias a: Ktron, Joseba, Alex y Jorge.
Si te ha gustado este artículo te animo a que te suscribas a la newsletter que envío cada domingo con publicaciones similares a esta y más contenido recomendado:
이번 주에 저는 일일 이메일 목록의 회원으로부터 이메일을 받았습니다. 그들은 알고 싶어했습니다. 매일, 매주, 매월 어떤 리소스를 방문합니까? 좋은 질문입니다! 제 작업 흐름과 제가 사용하는 주요 리소스에 대한 통찰력을 공유하게 되어 기쁩니다.
이 블로그 시리즈의 목적은 Lit 라이브러리를 깊이 탐구하고 Lit 라이브러리의 고유한 기능과 시장의 다른 라이브러리 및 프레임워크와 차별화되는 방법을 포괄적으로 이해하는 것입니다. 이 시리즈는 1과 같은 주제를 다루는 세 부분으로 나뉩니다.
낡은 것이 다시 새 것이 되고, 번쩍이던 것이 이제는 무디게 느껴진다. JNCO 청바지가 1990년대 후반의 다른 패션과 함께 시내의 쿨한 아이들 사이에서 컴백하는 것에 대해 말하는 것이 아닙니다.
Alyson Lee, 공무 관리 고문 연방 정부의 연간 예산 책정 과정은 이산화탄소 제거(CDR) 기금 마련을 위한 노력의 핵심입니다. 매년 Carbon180은 내년의 자금 흐름을 안내하기 위해 다양한 의회 사무소에 요청을 제출합니다.
나는 최근에 세계 최대의 전문 소셜 네트워크인 Linkedin에 있었고 내가 팔로우하는 프리랜서 디자이너의 게시물을 발견했는데 내 관심을 끌었습니다. 그들은 모두 비행기에서, 노트북과 함께 해변에서, 수영장에서, 멋진 전망이 있는 사무실에서 사진을 게시했습니다.
안녕하세요, 사이버 애호가 여러분! 위협 사냥 시리즈에 대한 OSINT에 다시 오신 것을 환영합니다. 첫 번째 기사에서는 OSINT에 대한 개요와 위협 사냥에서의 중요성에 대해 설명했습니다.