Map์ ๋๋์ด ์๊ธด getOrInsert: โ์์ผ๋ฉด ๋ฃ๊ณ , ์์ผ๋ฉด ๊บผ๋ด๊ธฐโ
๐ Overview
Map์ ์ฐ๋ค ๋ณด๋ฉด โํค๊ฐ ์์ผ๋ฉด ๊ธฐ๋ณธ๊ฐ์ ๋ฃ๊ณ , ๊ทธ ๊ฐ์ ๋ฐ๋ก ์ฌ์ฉํ๋คโ๋ ํจํด์ ๋์์ด ๋ฐ๋ณตํ๊ฒ ๋๋ค. ์ด ํจํด์ ๊ฐ๋จํ์ง๋ง ์ฝ๋๊ฐ ์ง์ ๋ถํด์ง๊ณ , ํ๋ง๋ค ๊ตฌํ ๋ฐฉ์์ด ๋ฌ๋ผ์ง๋ฉด์ ๊ฐ๋ ์ฑ์ด ๋ ๋จ์ด์ง๋ค.
Map.prototype.getOrInsert() / getOrInsertComputed() ๋ ์ด ๋ฐ๋ณต์ ํ์ค API๋ก ์ ๋ฆฌํ๋ค. ์ด ๊ธฐ๋ฅ์ ECMAScript 2026 ์คํ์ ํฌํจ๋ ์์ ์ด๋ฉฐ, ์ด์ ์ถ์๋ฅผ ์๋ ์์ ์ด๋ค. ์ค๋ ๊ธฐ๋ค๋ ธ๋ ๋งํผ ์ฌ์ฉ๋ฒ๊ณผ ์ฃผ์์ , ๊ทธ๋ฆฌ๊ณ ์์ ํ๊ฒ ๋์ ํ๋ ์๋ น์ ์ ๋ฆฌํด๋๋ ค ํ๋ค.
โ์์ผ๋ฉด ๋ฃ๊ณ ๊บผ๋ด๊ธฐโ๋ ์ฌ์ํ ๊ฐ์ ์ฒ๋ผ ๋ณด์ด์ง๋ง, ์๋น์ค ์ฝ๋์์๋ ๊ฐ์ฅ ์์ฃผ ๋ฑ์ฅํ๋ ๋ฐ๋ณต ์ค ํ๋๋ค.
1. Map์ ์ฌ์ฉํ ๋ ๊ฐ์ฅ ๋ง์ด ๋ฐ๋ณต๋๋ ์ฝ๋๊ฐ ์๋ค
๋๋ถ๋ถ์ ์ฝ๋๋ฒ ์ด์ค์์ Map์ ์ฐ๋ ์ด์ ๋ ๋ช ํํ๋ค. โํค โ ๊ฐโ ๊ด๊ณ๋ฅผ ๋น ๋ฅด๊ฒ ์กฐํํ๊ณ ์ถ๊ธฐ ๋๋ฌธ์ด๋ค. ๋ฌธ์ ๋ ๊ฐ์ด ์๋ ๊ฒฝ์ฐ๋ค.
์๋ฅผ ๋ค์ด, ๊ทธ๋ฃนํ(์นดํ ๊ณ ๋ฆฌ๋ณ๋ก ๋ฆฌ์คํธ ๋ง๋ค๊ธฐ)์ ๊ตฌํํ๋ฉด ๋๊ฐ ์ด๋ฐ ์ฝ๋๊ฐ ๋๋ค.
const groups = new Map();
function add(category, item) {
if (!groups.has(category)) {
groups.set(category, []);
}
groups.get(category).push(item);
}์ด ํจํด์ ๋ณธ์ง์ ๋จ์ํ๋ค.
- ํค๊ฐ ์์ผ๋ฉด ๊ธฐ์กด ๊ฐ์ ๊ฐ์ ธ์จ๋ค.
- ํค๊ฐ ์์ผ๋ฉด ๊ธฐ๋ณธ๊ฐ์ ๋ฃ๋๋ค.
- ๊ทธ ๊ฐ์ ๋ฐํ๋ฐ์ ์ด์ด์ ์ฌ์ฉํ๋ค.
ํ์ง๋ง ํํ์ ๋ ์ฅํฉํ๋ค. has โ set โ get์ด ํจ๊ป ๋ฌถ์ฌ ๋ค๋๋ค.
์ค์๋ ์์ฃผ ๋ฐ์ํ๋ค. set๋ง ํ๊ณ get์ ๋นผ๋จน๊ฑฐ๋, if/else๊ฐ ๋์ด๋๊ฑฐ๋, ๊ธฐ๋ณธ๊ฐ ์์ฑ์ด ๋น์ธ๋ ๋ฌด์กฐ๊ฑด ์คํ๋๋ ํํ๊ฐ ๋ง๋ค์ด์ง๋ค.
2. getOrInsert๋ โ์๋โ๋ฅผ ์ฝ๋๋ก ์ง์ ๋๋ฌ๋ธ๋ค
ECMAScript 2026์๋ ์๋ ๋ฉ์๋๊ฐ ์ถ๊ฐ๋๋ค.
- Map.prototype.getOrInsert(key, value)
- Map.prototype.getOrInsertComputed(key, fn)
- WeakMap.prototype.getOrInsert(key, value)
- WeakMap.prototype.getOrInsertComputed(key, fn)
ํต์ฌ ๋์์ ์ด๋ ๊ฒ ์ ๋ฆฌ๋๋ค.
- ํค๊ฐ ์์ผ๋ฉด ๊ธฐ์กด ๊ฐ์ ๋ฐํํ๋ค.
- ํค๊ฐ ์์ผ๋ฉด ์ ๊ฐ์ ๋ฃ๊ณ ๊ทธ ๊ฐ์ ๋ฐํํ๋ค.
- ๊ธฐ์กด ๊ฐ์ ๋ฎ์ด์ฐ์ง ์๋๋ค.
getOrInsert() ๋ ์๋ ์ฝ๋์ ๊ฐ์ ์๋ฏธ๋ค.
if (map.has(key)) {
return map.get(key);
}
map.set(key, defaultValue);
return defaultValue;์ด์ ๊ทธ๋ฃนํ ์ฝ๋๋ ์ด๋ ๊ฒ ๋ฐ๋๋ค.
const groups = new Map();
function add(category, item) {
groups.getOrInsertComputed(category, () => []).push(item);
}์กฐ๊ฑด๋ฌธ์ด ์ฌ๋ผ์ง๊ณ , โ์์ผ๋ฉด ์์ฑํด์ ๋ฃ๋๋คโ๋ ์๋๊ฐ ์ฝ๋์ ์ง์ ๋๋ฌ๋๊ธฐ ๋๋ฌธ์ ์ฝ๋ ์ฌ๋์ด ์ฝ๋์ ๋ชฉ์ ์ ๋ ๋นจ๋ฆฌ ์ดํดํ ์ ์๋ค.
3. getOrInsert์ getOrInsertComputed์ ์ฐจ์ด
๋ ๋ฉ์๋๋ ๋น์ทํด ๋ณด์ด์ง๋ง, ์ฉ๋๊ฐ ๋ช ํํ ๊ฐ๋ฆฐ๋ค.
-
getOrInsert(key, value)
const map = new Map(); map.getOrInsert("mode", "dark"); // "dark" map.getOrInsert("mode", "light"); // "dark" (๊ธฐ์กด ๊ฐ์ด ์์ผ๋ฏ๋ก ๋ฎ์ด์ฐ์ง ์์) map.getOrInsert(key, expensive()); // ์ฃผ์ ํ์์ฌ๊ธฐ์ ๋์์ ์ ํํ ์ดํดํด์ผ ํ๋ค. getOrInsert๋ โํค๊ฐ ์์ ๋ ๊ฐ์ ์ฝ์ โํ์ง๋ง, ํจ์ ์ธ์๋ ํธ์ถ ์ ์ ํ๊ฐ๋๋ค. ๋ฐ๋ผ์
getOrInsert(key, expensive())๋ ํค๊ฐ ์์ด๋expensive()๊ฐ ์คํ๋๋ค.expensive()๊ฐ ๊ฐ์ด ๋น์ผ ํจ์๋ผ๋ฉด, ์ง์ฐ ์์ฑ์ด ํ์ํ๋ฉฐ ๊ทธ๋ด ๊ฒฝ์ฐ์getOrInsertComputed(key, fn)์ ์ฌ์ฉํด์ผ ํ๋ค.
-
getOrInsertComputed(key, fn)
map.getOrInsertComputed("config", () => loadBigConfig());getOrInsertComputed๋ ํค๊ฐ ์์ ๋๋ง fn์ ์คํํ๋ค. ๊ธฐ๋ณธ๊ฐ ์์ฑ์ด ๋น์ธ๊ฑฐ๋(ํ์ผ ์ฝ๊ธฐ, ํ์ฑ, ํฐ ๊ฐ์ฒด ์์ฑ) ๋ถ์์ฉ์ด ์์ผ๋ฉด(๋ก๊ทธ ๋จ๊น, ์ธ๋ถ ํธ์ถ) getOrInsertComputed()๋ฅผ ์ฐ๋ ํธ์ด ๋ง๋ค.
4. ๋ฐ๋ก ์ฐ๋ ์์ 2๊ฐ์ง
4-1. ๊ทธ๋ฃนํ(๋ฉํฐ๋งต)
const groups = new Map();
function add(category, item) {
groups.getOrInsertComputed(category, () => []).push(item);
}
add("db", "PostgreSQL");
add("db", "Redis");
add("lang", "JavaScript");
console.log(groups.get("db")); // ["PostgreSQL", "Redis"]โ์์ผ๋ฉด ๋ฐฐ์ด์ ๋ง๋ค๊ณ , ์์ผ๋ฉด ๊ธฐ์กด ๋ฐฐ์ด์ ์ฐ๊ณ , ๋ฐ๋ก pushํ๋คโ๊ฐ ํ ์ค๋ก ํํ๋๋ค.
4-2. ์นด์ดํฐ/์ง๊ณ ๋ง๋ค๊ธฐ
const counts = new Map();
function hit(key) {
counts.set(key, counts.getOrInsert(key, 0) + 1);
}
hit("login");
hit("login");
hit("purchase");
console.log(counts.get("login")); // 2์ด ํจํด์ ๊ฐ์ข ์ง๊ณ(์ด๋ฒคํธ ์ง๊ณ, ์ํ ์นด์ดํ )์ ๊ทธ๋๋ก ์ธ ์ ์๋ค.
5. ์ฃผ์์ ์ด ์๋ค
์ด ๊ธฐ๋ฅ์ ๋จ์ํ์ง๋ง, ์์ฃผ ๋ฐ๋ ํจ์ ์ด ์กด์ฌํ๋ค.
-
getOrInsert(key, []) ๋ โ๋ถํ์ํ ๊ฐ์ฒด ์์ฑโ์ด ๋ฐ๋ณต๋ ์ ์๋ค
map.getOrInsert(key, []).push(value); // ๋ถํ์ํ ๊ฐ์ฒด ์์ฑ์ด ๋ฐ๋ณต๋ ์ ์๋ค. map.getOrInsertComputed(key, () => []).push(value);ํค๊ฐ ์ด๋ฏธ ์์ด๋ []๋ ํธ์ถ ์์ ๋ง๋ค ์์ฑ๋๋ค. ์ฌ์ฉ๋์ง ์์๋ ๊ฐ์ฒด ์์ฑ ๋น์ฉ์ ๋จ๋๋ค. ์ด ๊ฒฝ์ฐ๋ ์๋๊ฐ ์ ๋ต์ด๋ค.
-
โํค๊ฐ ์๋ ๊ฒโ๊ณผ โ๊ฐ์ด undefined ์ธ ๊ฒโ์ ๋ค๋ฅด๋ค
Map์ ๊ฐ์ผ๋กundefined๋ฅผ ๊ฐ์ง ์ ์๋ค. ๋ฐ๋ผ์ ์๋ ํจํด์ ์๋์ ๋ค๋ฅด๊ฒ ๋์ํ ์ ์๋ค.map.set("a", undefined); // ์ด ํจํด์ "undefined๋ฉด default"๋ก ์ทจ๊ธํ๋ค. // ๊ทธ๋ฐ๋ฐ "ํค๋ ์์ง๋ง ๊ฐ์ด undefined"์ธ ๊ฒฝ์ฐ๊น์ง default๋ก ๋ฐ๊ฟ๋ฒ๋ฆฐ๋ค. map.set("a", map.get("a") ?? "default");getOrInsert()๋ ๊ฐ์ด ์๋๋ผ โํค ์กด์ฌ ์ฌ๋ถโ ๋ก ํ๋จํ๋ฏ๋ก ์ด ์ ์ ์ฃผ์ํ์.
์คํ์ ํฌํจ๋์๋ค๊ณ ํด์ ๋ฐ๋ก ์ฌ์ฉํ ์ ์๋ ๊ฒ์ ์๋๋ค. ์ค์ ์ฌ์ฉ ๊ฐ๋ฅ ์ฌ๋ถ๋ ๋ธ๋ผ์ฐ์ ์ Node ๋ฒ์ ์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋ค. ๋ฐ๋ผ์ ๋์ ์ ์ ์ง์ ์ฌ๋ถ๋ฅผ ๋จผ์ ํ์ธํ๋ ํธ์ด ์์ ํ๋ค.
6. ์ต์ ์คํ์ ๋ฏธ๋ฆฌ ์์๋ณด๋ ๋ฐฉ๋ฒ
์คํ์ ๊น๊ฒ ํ๋ ๊ฒ๋ณด๋ค, โ๋ณํ์ ์ ํธโ๋ฅผ ๋นจ๋ฆฌ ์ก๋ ํธ์ด ํจ์จ์ ์ด๋ค. ์๋ ๋ฃจํด๋ง ์ฑ๊ฒจ๋ ๋๋ถ๋ถ์ ์ ๊ธฐ๋ฅ์ ๋์น์ง ์๋๋ค.
6-1. GitHub๋ โ๊ด์ฌ ํค์๋๋งโ Star๋ก ๋ชจ์๋๋ค
GitHub๋ ์คํ ๋ณํ๊ฐ ๊ฐ์ฅ ๋จผ์ ๋ชจ์ด๋ ๊ณณ์ด๋ค. ๋ค๋ง ๋ชจ๋ Discussion์ ๋ฐ๋ผ๊ฐ๋ ค ํ๋ฉด ๊ธ๋ฐฉ ์ง์น๋ค. ๊ทธ๋์ ๋๋ โ์ธ๋ฑ์ค ์ ์ฅ์ + ๊ด์ฌ ์ ์ ์ ์ฅ์โ๋ง Star๋ก ๋ชจ์๋๋ ๋ฐฉ์์ผ๋ก ๊ด๋ฆฌํ๋ค.
๋จผ์ , ๊ธฐ์ค์ด ๋๋ ์ธ๋ฑ์ค 2๊ฐ๋ง ์ก์๋๋ค.
- tc39/proposals๋ ์งํ ์ค์ธ ECMAScript ์ ์๋ค์ ์ถ์ ํ๋ ๋ชฉ๋ก์ด๋ค.
- tc39/ecma262๋ ํ์ค ์คํ ๋ณธ๋ฌธ์ด ๋ชจ์ด๋ ์ ์ฅ์์ด๋ฉฐ, ์ ์์ proposals์์ ๊ด๋ฆฌ๋๋ค๋ ์๋ด๊ฐ ๋ค์ด ์๋ค.
๊ทธ๋ฆฌ๊ณ โ๋ด๊ฐ ๊ด์ฌ ์๋ ๊ธฐ๋ฅโ๋ง ์ถ๊ฐ๋ก Starํ๋ค. ์๋ฅผ ๋ค์ด ์ด๋ฒ ๊ธ์ ์ฃผ์ ๋ ์๋ ์ ์ฅ์์์ ์์ํ๋ค.
tc39/proposal-upsert (๊ฒฐ๊ณผ์ ์ผ๋ก getOrInsert / getOrInsertComputed๋ก ์ ๋ฆฌ๋ ์ ์)
GitHub๋ Starํ ์ ์ฅ์๋ฅผ List๋ก ๋ถ๋ฅํ ์ ์๋ค. ๋๋ ์ด ๊ธฐ๋ฅ์ Spec Radar ๊ฐ์ ์ด๋ฆ์ผ๋ก ์จ์ ๊ด์ฌ ์๋ ์คํ ๊ด๋ จ ์ ์ฅ์๋ง ๋ฐ๋ก ๋ชจ์๋๋ค. ์๋๋ ๋ด๊ฐ ์ํ๋ก Starํด์ Spec Radar ๋ฆฌ์คํธ์ ๋ฃ์ด๋ ๊ตฌ์ฑ ์์๋ค. (๊ด์ฌ์ฌ์ ๋ง๊ฒ ๋ฐ๊พธ๋ฉด ๋๋ค.)
์ด ์ ๋๋ง ๋ชจ์๋ฌ๋ โ์์ฆ ์๋ฐ์คํฌ๋ฆฝํธ๊ฐ ์ด๋๋ก ๊ฐ๋์งโ ๊ฐ์ด ์๊ธด๋ค.
์ถ๊ฐ๋ก, ์๋ฆผ(Watch)์ ์ต์๋ก ์ผ๋ ํธ์ด ๋ซ๋ค. ์๋ฆผ์ด ๋ง์์ง๋ฉด ๊ฒฐ๊ตญ ๋ค ๊บผ๋ฒ๋ฆฌ๊ฒ ๋๋ค. ๊ทธ๋์ ๋๋ Star + ๋ฆฌ์คํธ๋ก ์ ๋ฆฌํ๊ณ , ์ ๋ง ๊ด์ฌ ์๋ ์ ์ฅ์๋ง ์ ๋ณ์ ์ผ๋ก Watchํ๋ค.
6-2. ๊ฒฐ๊ตญ์ ๋ฐํ์ ๋ฆด๋ฆฌ์ฆ ๋ ธํธ๋ฅผ ๋ณธ๋ค
์คํ์ ๋ค์ด๊ฐ๋ค๊ณ ๋์ด ์๋๋ค. ์ค์ ๋ก๋ ๋ธ๋ผ์ฐ์ /Node ๋ฆด๋ฆฌ์ฆ์ ๋ค์ด๊ฐ๋ ์๊ฐ๋ถํฐ๊ฐ ์ค์ ์ด๋ค. ๋ฐ๋ผ์ โ๋ด๊ฐ ๋ฐฐํฌํ๋ ๋ฐํ์โ์ ๋ฆด๋ฆฌ์ฆ ๋ ธํธ๋ฅผ ๊ฐ๋ ํ๋ ์ต๊ด์ด ๊ฐ์ฅ ๊ฐ๋ ฅํ๋ค. ์คํ๋ณด๋ค ๋ฐํ์์ด ๋ ํ์ค์ด๋ค.
๐ค Understanding
Map.getOrInsert() ๋ ๊ฑฐ๋ํ ๊ธฐ๋ฅ์ด ์๋๋ค. ํ์ง๋ง ์ธ์ด๊ฐ ๊ฐ๋ ๋ฐฉํฅ์ ๋๋ ทํ๊ฒ ๋ณด์ฌ์ฃผ๋ ๋ณํ๋ค. ์๋ฐ์คํฌ๋ฆฝํธ๋ ๊ณ์ํด์ โ๊ฐ๋ฅ์ ํ์ง๋ง ๋ ์ฅํฉํ๋ ํจํดโ์ ํ์ค API๋ก ๋์ด์ฌ๋ฆฌ๊ณ ์๋ค. ๊ทธ ๊ฒฐ๊ณผ ์ฝ๋์ ์๋๊ฐ ๋ ๋ช ํํด์ง๋ค๋ ์ ์ด ์ค์ํ๋ค.
๋น์ทํ ๊ฒฝํ์ ES2024์ Object.groupBy / Map.groupBy ์์๋ ๋๊ผ๋ค.
๊ณผ๊ฑฐ์๋ ๊ทธ๋ฃนํ์ ํ๋ ค๋ฉด reduce๋ก ๋์ ๊ฐ์ฒด๋ฅผ ๋ง๋ค๊ณ , ํค๊ฐ ์์ผ๋ฉด ์ด๊ธฐํํ๊ณ , ๊ทธ ๋ค์ pushํ๋ ํ๋ฆ์ ์ง์ ์์ฑํด์ผ ํ๋ค. ๋์ ์์ฒด๋ ๋จ์ํ์ง๋ง ํํ์ด ๊ธธ๊ณ , ๊ตฌํ ๋ฐฉ์๋ ํ๋ง๋ค ๋ฌ๋๋ค. groupBy๊ฐ ๋ค์ด์ค๋ฉด์ โ๊ทธ๋ฃนํ์ ํ๋คโ๋ ์๋๊ฐ ์ฝ๋์ ์ง์ ๋๋ฌ๋๊ธฐ ์์ํ๋ค.
์ด๋ฒ getOrInsert๋ ๊ฐ์ ๊ฒฐ์ด๋ค. has โ set โ get์ ๋ฐ๋ณตํ๋ ๋์ โ์์ผ๋ฉด ๋ฃ๊ณ ๊บผ๋ธ๋คโ๋ ์๋๊ฐ ํ ์ค๋ก ๊ณ ์ ๋๋ค. ํนํ getOrInsertComputed๋ ๊ธฐ๋ณธ๊ฐ ์์ฑ ๋น์ฉ๊น์ง ์๋์ ๋ง๊ฒ ์ง์ฐ์ํค๋ฉด์, ์ฝ๋๊ฐ ๋งํ๊ณ ์ ํ๋ ๋ฐ๋ฅผ ๋ ์ ํํ ํํํ๋ค.
์ด๋ฐ ๋ณํ๊ฐ ๋ง์์ ๋ ๋ค. ์๋ฐ์คํฌ๋ฆฝํธ๋ ์ฌ์ ํ ์ ์ฐํ ์ธ์ด์ด์ง๋ง, ์์ฃผ ์ฐ๋ ํจํด์ ํ์ค API๋ก ์ ๋ฆฌํด ์ฝ๋ ์ฌ๋ ์ค์ฌ์ ์ฝ๋๋ก ์ ๋ํ๊ณ ์๋ค. ๊ตฌํ์ ์จ๊ธฐ๋ ๊ฒ์ด ์๋๋ผ, ๋ฐ๋ณต๋๋ ์๋๋ฅผ ๊ณตํต ์ธ์ด๋ก ์ฌ๋ ค์ฃผ๋ ๋ฐฉํฅ์ด๋ค. groupBy์ getOrInsert๋ ๊ทธ ํ๋ฆ์ ์ ๋ณด์ฌ์ฃผ๋ ํ ์์ ์ฌ๋ก๋ผ ์๊ฐ๋๋ค.