add, delete, has, clear ๋ฑ)์ ๋ํ ์์ ๋ฅผ ๋ ์ฌ๋ ค๋ณธ๋ค.์๋ฐ์คํฌ๋ฆฝํธ์ Map๊ณผ Set์ ES6์์ ๋์ ๋ ์๋ก์ด ์ปฌ๋ ์ ์๋ฃ๊ตฌ์กฐ์ ๋๋ค.
Map์ ํค์ ๊ฐ์ ํ ์์ผ๋ก ์ ์ฅํ๋ค๋ ์ ์์ ๊ฐ์ฒด์ ๋น์ทํ์ง๋ง,
๋ชจ๋ ํ์ ์ ๊ฐ์ ํค๋ก ์ฌ์ฉํ ์ ์๊ณ , ํค์ ์ฝ์ ์์๋ฅผ ์ ์งํ๋ค๋ ์ฐจ์ด๊ฐ ์์ต๋๋ค.
๊ทธ๋์ ์ฃผ๋ก ์์๊ฐ ์ค์ํ๊ฑฐ๋, ๊ฐ์ฒด ํค ์ธ์ ๊ฐ์ ํค๋ก ์ฌ์ฉํด์ผ ํ ๋ ํ์ฉ๋ฉ๋๋ค.
์๋ฅผ ๋ค์ด API ์๋ต ์บ์ฑ, DOM ์์๋ณ ๋ฐ์ดํฐ ๋งคํ ๊ฐ์ ๊ฒฝ์ฐ์ ์ ์ฉํฉ๋๋ค.๋ฐ๋ฉด Set์ ์ค๋ณต๋์ง ์๋ ์ ์ผํ ๊ฐ์ ์งํฉ์ ์ ์ฅํ๋ ์๋ฃ๊ตฌ์กฐ์ ๋๋ค.
๊ฐ์ด ํ ๋ฒ๋ง ์กด์ฌํด์ผ ํ๋ ์ํฉ, ์๋ฅผ ๋ค์ด ์ค๋ณต ์ ๊ฑฐ, ๋ฐฐ์ด์์ ๊ณ ์ ํ ๊ฐ ์ถ์ถ ๋ฑ์ ์์ฃผ ์ฌ์ฉ๋ฉ๋๋ค.
์ฝ์ ์์๋ ์ ์ง๋๊ธฐ ๋๋ฌธ์ ์ํ ์์๋ ์์ ์ ์ ๋๋ค.๋ ๊ตฌ์กฐ ๋ชจ๋
size,has,delete,clear๊ฐ์ ๋ฉ์๋๋ฅผ ์ ๊ณตํด ๋ฐ์ดํฐ ๊ด๋ฆฌ๊ฐ ๊ฐ์ฒด๋ณด๋ค ํจ์ฌ ์ง๊ด์ ์ด๊ณ ํจ์จ์ ์ ๋๋ค.
NaN ๋ฑ)์ธ์ ์ฐ๋?
๋ฌธ์์ด ์ด์ธ์ ๊ฐ(์: ๊ฐ์ฒด, ํจ์)์ ํค๋ก ์จ์ผ ํ ๋
const map = new Map();
const user = { id : 1 };
function handler() {}
const notANumber = NaN;
map.set(user, { role: "admin" });
map.set(handler, { once: true });
map.set(notANumber, "special");
// ๋์ผ ์ฐธ์กฐ๋ก ์กฐํ ๊ฐ๋ฅ
console.log(map.get(user)); // { role: "admin" }
console.log(map.get(handler)); // { once: true }
console.log(map.get(NaN)); // "special"
- ๊ฐ์ฒด(
Object)์ ํค๋ ๋ฌธ์์ด/์ฌ๋ณผ๋ก ๊ฐ์ ๋จ (๊ฐ์ฒด๋ฅผ ํค๋ก ๋ฃ์ผ๋ฉด ๋ฌธ์์ด๋ก ๋ณํ๋์ด ์ถฉ๋/์๋์น ์์ ๋์ ๋ฐ์)Map์ ๋ชจ๋ ํ์ ์ ํค๋ก ์์ ํ๊ฒ ์ฌ์ฉ ๊ฐ๋ฅ, ์ฝ์ ์์ ์ ์งMap์ ํค๋ฅผ ๋ฌธ์์ด๋ก ๋ณํํ์ง ์๊ณ , "๊ทธ ๊ฐ์ฒด ์ฐธ์กฐ ์์ฒด"๋ฅผ ํค๋ก ์- ์ฆ,
{ id: 1 }๊ทธ ๊ฐ์ฒด(๋ฉ๋ชจ๋ฆฌ ์์ ์ฐธ์กฐ)๊ฐ ๊ทธ๋๋ก ํค๋ก ์ ์ฅ๋จ- ๊ทธ๋์ ๋์ผํ ๋ชจ์์ ๋ค๋ฅธ ๊ฐ์ฒด๋ ํค๊ฐ ๋ค๋ฆ
const user1 = { id: 1 }; const user2 = { id: 2 }; // ๋ด์ฉ ๊ฐ์๋ ๋ค๋ฅธ ๊ฐ์ฒด(์ฐธ์กฐ ๋ค๋ฆ) const map = new Map(); map.set(user1, "A"); map.get(user1); // "A" map.get(user2); // undefined (๋ฌธ์์ด ํค์๋ค๋ฉด ์ถฉ๋/ํผ๋์ด ์๊ฒผ์ ๋ถ๋ถ)
ํค ๊ฐ์๋ฅผ ์์ฃผ ํ์ธํ ๋(size) (์: ๊ฐ๋จ LRU ์บ์ ํธ๋ฆฌ๋ฐ)
// ์ต๋ N๊ฐ๊น์ง๋ง ๋ณด๊ดํ๋ ์บ์: size๋ก ์ฆ์ ํ๋จ ํ ๊ฐ์ฅ ์ค๋๋ ํญ๋ชฉ ์ ๊ฑฐ
const MAX = 3;
const cache = new Map();
function setCache(key, value) {
if (cache.size >= MAX) {
// ๊ฐ์ฅ ๋จผ์ ๋ค์ด์จ(๊ฐ์ฅ ์ค๋๋) ํค๋ฅผ ํ๋ ์ ๊ฑฐ
const oldestKey = cache.keys().next().value;
cache.delete(oldestKey);
}
cache.set(key, value);
}
setCache("a", 1); // size: 1
setCache("b", 2); // size: 2
setCache("c", 3); // size: 3
setCache("d", 4); // size๊ฐ 3์ ๋๊ธฐ ์ง์ ์ด๋ฏ๋ก 'a' ์ ๊ฑฐ
console.log([...cache.entries()]); // [ ['b', 2], ['c', 3], ['d', 4] ]
console.log(cache.size); // 3
๐ป
cache.keys()
Map์ ํค ์ดํฐ๋ ์ดํฐ(Iterator)๋ฅผ ๋๋ ค์ค- ์ด ์ดํฐ๋ ์ดํฐ๋
for...of๋ก ๋๋ฆด ์ ์๊ณ , ๋ด๋ถ ์์๋ ์ฝ์ ์์์๐ป
.next()
- ์ดํฐ๋ ์ดํฐ์์ ๋ค์ ํญ๋ชฉ ํ๋๋ฅผ ๊บผ๋ด๋ผ๋ ๋ป
- ๋ฐํ๊ฐ์
{ value: <ํค๊ฐ>, done: <๋ถ๋ฆฌ์ธ> }ํํ์ IteratorResult ๊ฐ์ฒด
value: ์ด๋ฒ์ ๊บผ๋ธ ์์done: ๋ ๊บผ๋ผ ๊ฒ ์์ผ๋ฉดtrue, ์์ผ๋ฉดfalse๐ป
.value
- ์์์ ๋ฐ์ ๊ฐ์ฒด์์ ํค ๊ฐ๋ง ์ถ์ถํจ
- ์ฆ, ์ฒซ ๋ฒ์งธ(๊ฐ์ฅ ์ค๋๋) ํค๊ฐ ๋ค์ด์ด
Map.size๋ O(1)๋ก ์ฆ์ ํ์ธ ๊ฐ๋ฅ- ๊ฐ์ฒด๋ ํค ๊ฐ์ ๊ณ์ฐ ์
Object.keys(obj).length์ฒ๋ผ ๋งค๋ฒ ์ํ ๋น์ฉ์ด ๋ฆ- ์บ์/๋ฒํผ์ฒ๋ผ ์ฉ๋ ๊ด๋ฆฌ๊ฐ ํ์ํ ๊ณณ์ ์ ๋ฆฌํจ
์์๊ฐ ์ค์ํ ๋งคํ, ์บ์, ๋น๋/์นด์ดํธ ํ ์ด๋ธ ๋ฑ
์์ ๋ณด์กด ๋งคํ: ํผ ํ๋ - ๋ผ๋ฒจ/๊ฒ์ฆ ์์๋๋ก ๋ ๋๋ง
const fieldMap = new Map([
["email", { label: "์ด๋ฉ์ผ", required: true }],
["password", { label: "๋น๋ฐ๋ฒํธ", required: true }],
["nickname", { label: "๋๋ค์", required: false }],
]);
// ์ฝ์
์์๋๋ก UI ๋ ๋
for (const [name, meta] or fieldMap) {
console.log(`{meta.label} (${meta.required ? "ํ์" : "์ ํ"})`);
}
// ์ถ๋ ฅ ์์: ์ด๋ฉ์ผ โ ๋น๋ฐ๋ฒํธ โ ๋๋ค์
์บ์(์ต๊ทผ ์ฐธ์กฐ๋ฅผ ๋ค๋ก ๋ฐ๊ธฐ) - ๊ฐ๋จํ LRU ์ ๊ทผ
const cache = new Map();
function get(key) {
if (!cache.has(key)) return undefined;
const val = cache.get(key);
// ์ฌ์ฉ๋ ํญ๋ชฉ์ '์ต์ '์ผ๋ก ๋ง๋ค๊ธฐ ์ํด ์ญ์ ํ ์ฌ์ฝ์
โ ์์ ๋ค๋ก ์ด๋
cache.delete(key);
cache.set(key, val);
return val;
}
function put(key, val, max = 3) {
if (cache.has(key)) cache.delete(key);
cache.set(key, val);
if (cache.size > max) {
const oldestKey = cache.keys().next().value;
cache.delete(oldestKey);
}
}
put("A", 1); put("B", 2); put("C", 3); // A, B, C
get("A"); // A๋ฅผ ์ต๊ทผ์ผ๋ก: B, C, A
put("D", 4); // ์ด๊ณผ: ๊ฐ์ฅ ์ค๋๋ B ์ ๊ฑฐ
console.log([...cache.keys()]); // ['C', 'A', 'D']
๋น๋/์นด์ดํธ ํ ์ด๋ธ (๋จ์ด ๋ฑ์ฅ ์์ ์ ์งํด ํต๊ณ ์ถ๋ ฅ)
function frequency(list) {
const freq = new Map();
for (const item of list) {
freq.set(item, (freq.get(item) ?? 0) + 1);
}
return freq; // ์ฝ์
์์(์ฒซ ๋ฑ์ฅ ์์)๋ ํจ๊ป ๋ณด์กด
}
const words = ["a", "b", "a", "c", "b", "a"];
const table = frequency(words);
for (const [word, count] of table) {
console.log(`${word}: ${count}`);
}
// a: 3 โ b: 2 โ c: 1 (์ฒซ ๋ฑ์ฅ ์์๋๋ก)
map.sizemap.has(key)map.set(key, value) (๋์ผ ํค๋ฉด ๊ฐฑ์ )map.get(key) (์์ผ๋ฉด undefined)map.delete(key), map.clear()for (const [k, v] of map), map.forEach((v, k) => ...)๐ SameValueZero๋?
๊ฐ๋
- ์๋ฐ์คํฌ๋ฆฝํธ์์ ๊ฐ์ "๊ฐ์"์ ํ๋จํ๋ ๊ท์น(๋๋ฑ ๋น๊ต ์๊ณ ๋ฆฌ์ฆ) ์ค ํ๋
- ๋๋ถ๋ถ
===์ฒ๋ผ ๋น๊ตํ์ง๋งNaN์ ์๋ก ๊ฐ๋ค๊ณ ๋ณด๊ณ ,+0๊ณผ-0๋ ๊ฐ๋ค๊ณ ๋ด๋น๊ต ๊ท์น ์ฐจ์ดํ
๋น๊ต ๊ท์น NaNvs.NaN+0vs.-0๊ฐ์ฒด ๋น๊ต ===(์๊ฒฉ ๋๋ฑ)falsetrue์ฐธ์กฐ ๋์ผ์ฑ SameValueZero truetrue์ฐธ์กฐ ๋์ผ์ฑ Object.istruefalse์ฐธ์กฐ ๋์ผ์ฑ โ ์ฐธ์กฐ ๋์ผ์ฑ(reference equality)
- "๋ ๊ฐ์ด ๋ฉ๋ชจ๋ฆฌ์์ ๊ฐ์ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํค๋๋?"๋ฅผ ๋ฌป๋ ๊ฐ๋
- ๋ ํผ์ฐ์ฐ์๊ฐ ๋์ผํ ๊ฐ์ฒด ์ธ์คํด์ค(๊ฐ์ ์ฐธ์กฐ)๋ฅผ ๊ฐ๋ฆฌํค๋ฉด
true, ์๋๋ฉดfalse์ ์ค์ํ๊ฐ?
Map/Set์ ํค(๋๋ ๊ฐ) ๋๋ฑ์ฑ์ SameValueZero๋ก ํ๋จํจ
๊ทธ๋์NaN์ ํค๋ก ์จ๋ ์ ์ ๋์ํจconst m = new Map(); m.set(NaN, 'ok'); console.log(m.get(NaN)); // 'ok' (NaN๋ ๊ฐ์ ํค๋ก ์ธ์) const s = new Set([NaN, NaN]); console.log(s.size); // 1 (์ค๋ณต์ผ๋ก ํ๋จํจ)๋ฐ๋ฉด ๋ฐฐ์ด ๊ฒ์์ ๊ท์น์ด ๋ค๋ฅผ ์ ์์
const array = [NaN]; array.indexOf(NaN); // -1 (indexOf๋ === ๊ท์น ์ ์ฉ) array.includes(NaN); // true (includes๋ SameValueZero ๊ท์น ์ ์ฉ)
for (const [k, v] of m.entries()) {}
for (const k of m.keys()) {}
for (const v of m.values()) {}const m2 = new Map(Object.entries({ a: 1, b: 2 }));
const obj = Object.fromEntries(m2); // { a: 1, b: 2 }๐ป
Object.entries({ a: 1, b: 2 })
- ๋ฐํ:
[['a', 1], ['b', 2]]ํํ์ [ํค, ๊ฐ] ํํ ๋ฐฐ์ด- ํฌํจ ๋ฒ์: ์ด๊ฑฐ ๊ฐ๋ฅํ(enumerable) ๋ฌธ์์ด ํค๋ง ํฌํจ
- ๋น์ด๊ฑฐ ํ๋กํผํฐ๋ ์ ์ธ
- Symbol ํค๋ ์ ์ธ
- ํค ํ์ : ๋ฌธ์์ด๋ก ๋์ด์ด
๐ป
new Map(<iterable>)
- Map ์์ฑ์๋
[key, value]์๋ค์ ์ดํฐ๋ฌ๋ธ์ ๋ฐ์- ์์์ ๋ฐ์
[['a', 1], ['b', 2]]๋ฅผ ๋ฃ์ผ๋ฉด
m2.get('a') === 1,m2.get('b') === 2- ์ฝ์ ์์ ์ ์ง
- ํฌ์ธํธ: ์ด ๊ฒฝ์ฐ ํค๊ฐ ๋ฌธ์์ด์ด์ง๋ง, Map์ ์๋ ๋ชจ๋ ํ์ ์ ํค๋ก ์ธ ์ ์์(๊ฐ์ฒด, ํจ์, NaN ๋ฑ)
๐ป
Object.fromEntries(m2)
- ์ญํ :
[key, value]์์ ์ดํฐ๋ฌ๋ธ์ ๊ฐ์ฒด ๋ฆฌํฐ๋ด๋ก ๋ณํm2๋ ์ดํฐ๋ฌ๋ธ(Map์ ๊ธฐ๋ณธ ์ํ๊ฐ[key, value])์ด๋ฏ๋ก ๊ทธ๋๋ก ์ ๋ฌ ๊ฐ๋ฅ- ๊ฒฐ๊ณผ:
{ a: 1, b: 2 }
const m3 = new Map([["x", 10], ["y", 20]]);
const arr = [...m3]; // [ ["x", 10], ["y", 20] ]const cache = new Map();
async function fetchWithCache(url) {
// ์บ์์ ์์ผ๋ฉด ์ฆ์ ๋ฐํ(O(1)))
if (cache.has(url)) return cache.get(url);
// ์บ์์ ์์ผ๋ฉด fetch โ JSON ํ์ฑ
const res = await fetch(url).then(r => r.json());
// ๊ฒฐ๊ณผ๋ฅผ ์บ์์ ์ ์ฅ
cache.set(url, res);
// ํธ์ถ์์ ๋ฐํ
return res;
}๐ซ ๋์ ํฌ์ธํธ
cache๋Map<string, any>์ญํ : ํค๋ URL ๋ฌธ์์ด, ๊ฐ์ ํ์ฑ๋ ์๋ต ๊ฐ์ฒดcache.has(url)โcache.get(url)์ ์กฐํฉ์ผ๋ก ์บ์ ํํธ๋ฅผ O(1)๋ก ์ฒ๋ฆฌ- ์ต์ด ์์ฒญ(๋ฏธ์ค)์ผ ๋๋ง
fetch๋ฅผ ์ํํ๊ณ ์๋ต์setํ์ฌ ๋ค์ ํธ์ถ ์ต์ ํMap์ ์ฐ๋ ์ด์ :size/has/get/set์ด ๋น ๋ฅด๊ณ , ํค ์ถฉ๋ ์์ด ๋ฌธ์์ด ํค๋ฅผ ๊ทธ๋๋ก ์ฌ์ฉ๐ซ ์ค๋ฌด์์ ๋ฐ๋ก ์๊ฐํด์ผ ํ ๊ฒ๋ค
- ์์ฒญ ์ค๋ณต(๋์์ฑ) ์ด์
๋์์ ๊ฐ์ URL์ด ์ฌ๋ฌ ๋ฒ ํธ์ถ๋๋ฉด, ์ ์ฝ๋์์ ์ค๋ณต fetch๊ฐ ๋ฐ์ํ ์ ์์
โ "์งํ ์ค์ธ ํ๋ผ๋ฏธ์ค"๋ฅผ ์บ์์ ์ ์ฅํ๋ฉด ํด๊ฒฐ๋จconst cache = new Map(); async function fetchWithCache(url) { if (cache.has(url)) return cache.get(url); // ๊ฐ ๋๋ ํ๋ผ๋ฏธ์ค ๋ชจ๋ ๋ฐํ ๊ฐ๋ฅ const p = fetch(url) .then(r => { if (!r.ok) throw new Error(`HTTP ${r.status}`); return r.json(); }) .then(data => { cache.set(url, data); // ์๋ฃ ํ ์ค์ ๋ฐ์ดํฐ๋ก ์นํ return data; }) .catch(err => { cache.delete(url); // ์คํจ ์ ์บ์์์ ์ ๊ฑฐ (๋ถ๋ ํ๋ผ๋ฏธ์ค ๋จ์ง ์๊ฒ) throw err; }); cache.set(url, p); // "์งํ ์ค์ธ ํ๋ผ๋ฏธ์ค" ์บ์ฑ โ ์ค๋ณต ์์ฒญ ๋ฐฉ์ง return p; }- ๋ง๋ฃ(TTL)/๋ฌดํจํ
๋ฐ์ดํฐ๊ฐ ์ค๋๋๋ฉด ๊ฐฑ์ ํด์ผ ํจ
โ ๊ฐ๋จํ ํ์์คํฌํ๋ฅผ ํจ๊ป ์ ์ฅํ๊ฑฐ๋ LRU + TTL์ ๋์ ํจconst cache = new Map(); // url -> { data, ts } const TTL = 60_000; // 60s async function fetchWithTTL(url) { const hit = cache.get(url); const now = Date.now(); if (hit && now - hit.ts < TTL) return hit.data; const data = await fetch(url).then(r => r.json()); cache.set(url, { data, ts: now }); return data; }- ํค ์ค๊ณ
- ์ฟผ๋ฆฌ์คํธ๋ง์ด ๋ค๋ฅด๋ฉด ๋ค๋ฅธ ๋ฆฌ์์ค๋ก ๊ฐ์ฃผ:
?page=1vs.?page=2POST/ํค๋/๋ฐ๋์ ๋ฐ๋ผ ๊ฒฐ๊ณผ๊ฐ ๋ฌ๋ผ์ง ์ ์์ โ ์์ฒญ ํ๋ผ๋ฏธํฐ๋ฅผ ์ง๋ ฌํํด ํค๋ก ํฌํจํด์ผ ํจ- ์ธ์ฆ ํ ํฐ, ๋ก์ผ์ผ ๋ฑ๋ ์บ์ ํค์ ๋ฐ์ ํ์
- ์๋ฌ ์ฒ๋ฆฌ
response.ok์ฒดํฌ, ๋คํธ์ฟผ์ผ ์๋ฌ ํธ๋ค๋ง, ์คํจ ์ ์ฌ์๋/๋ฐฑ์คํ ์ ๋ต ๊ณ ๋ ค- ์คํจ ์๋ต์ ์บ์ํ๋ฉด ์ ๋๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ โ ์คํจ ์ ์บ์ ์ ๊ฑฐ
- ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ
- ๋ฌดํํ ์์ด์ง ์๊ฒ ์ต๋ ์ฉ๋์ ๋๊ณ LRU๋ก ์ ๊ฑฐ
- ํญ ์ด๋/์ฑ ์ข ๋ฃ ์ ์ฌ๋ผ์ง๋ ํ๋ก์ธ์ค ๋ฉ๋ชจ๋ฆฌ ์บ์์์ ์ดํดํด์ผ ํจ (์์์ฑ ํ์ํ๋ฉด IndexedDB/Cache Storage ๊ณ ๋ ค)
- ๋ณด์/๋ฏผ๊ฐ ๋ฐ์ดํฐ
- ์ฌ์ฉ์๋ณ๋ก ๋ค๋ฅธ ๊ฒฐ๊ณผ๊ฐ ๋์ค๋ ๊ฐ์ธํ ๋ฐ์ดํฐ๋ ์ฌ์ฉ์ ์ปจํ ์คํธ ๋จ์๋ก ๋ถ๋ฆฌํ๊ฑฐ๋ ์บ์ ๊ธ์ง
๐ซ ์ธ์ ์ ์ฉํ๊ฐ?
- ๋์ผ URL์ ์งง์ ์๊ฐ ์์ ๋ฐ๋ณต ํธ์ถํ๋ ํ๋ฉด (๋ฆฌ์คํธ ์ฌ๋ฐฉ๋ฌธ, ํญ ์ ํ, ๋ฌดํ ์คํฌ๋กค์ ์ฌ์์ฒญ ๋ฑ)
- ์๋ฒ์ ์บ์ ํค๋๊ฐ ์๊ฑฐ๋, ํด๋ผ์ด์ธํธ ๋ ๋ฒจ์์ ๋ ๊ณต๊ฒฉ์ ์ผ๋ก ์ต์ ํํ๊ณ ์ถ์ ๋
function countBy(arr) {
const map = new Map();
for (const v of arr) map.set(v, (map.get(v) ?? 0) + 1);
return map;
}๐ซ ์ฝ๋์ ์ญํ
- ์ ๋ ฅ ๋ฐฐ์ด
arr์ ๊ฐ์ ๊ฐ ํค๋ก, ๊ทธ ๋ฑ์ฅ ํ์๋ฅผ ๊ฐ์ผ๋ก ๊ฐ๋Map์ ๋ง๋ค์ด ๋ฐํํจ- ๊ฒฐ๊ณผ
Map์ ์์๋ ํด๋น ๊ฐ์ด ์ฒ์ ๋ฑ์ฅํ ์์๋ฅผ ๋ฐ๋ฆ (์ฝ์ ์์ ์ ์ง)๐ซ ๋จ๊ณ๋ณ ๋์
const map = new Map();
- ๋น ์นด์ดํธ ํ ์ด๋ธ ์์ฑ
for (const v of arr)
- ๋ฐฐ์ด์ ์์ฐจ ์ํ
map.set(v, (map.get(v) ?? 0) + 1);
- ํ์ฌ ๊ฐ
v์ ๊ธฐ์กด ์นด์ดํธ๋ฅผ ์ฝ๊ณ (map.get(v))- ์์ผ๋ฉด
undefined์ด๋ฏ๋ก ๋ ๋ณํฉ ์ฐ์ฐ์(Nullish Coalescing Operator)??๋ก 0์ ๋์ ์ฌ์ฉ+ 1ํด์ ๋ค์ ์ ์ฅํจreturn map;
Map<๊ฐ, ์นด์ดํธ>๋ฐํ๐ซ ์์ฃผ ํ๋ ์ค์
map.set(v, (map.get(v) || 0) + 1)
||๋ 0์ด๋ ""(๋น ๋ฌธ์์ด)๋ "์์"์ผ๋ก ์ฒ๋ฆฌํ๋ฏ๋ก ๋น์ถ์ฒ- ์ด ์ฝ๋๋ ํ์ฌ ๋งฅ๋ฝ์์๋ ์ ์์ ์ผ๋ก ๋์ํ์ง๋ง ์ต๊ดํํ๋ฉด ๋ค๋ฅธ ์ํฉ์์ ๋ฒ๊ทธ๋ฅผ ์ ๋ฐํ ์ ์์
- ๋ฐ๋ผ์ ํญ์
??์ ์ฌ์ฉํ๋ ๊ฒ์ด ์์ ํจ
const dataByEl = new Map();
function bind(el, data) { dataByEl.set(el, data); }
function getData(el) { return dataByEl.get(el); }๐ซ ์ญํ
dataByEl
Map<Node, any>์ญํ ์ ํจ- ํค: DOM ์์(๋๋ ์์์ ๊ฐ์ฒด) ์ฐธ์กฐ
- ๊ฐ: ๊ทธ ์์์ ์ฐ๊ฒฐํด ๋๊ณ ์ถ์ ์์์ ๋ฐ์ดํฐ(์ํ, ์ต์ , ๋ฉํ์ ๋ณด ๋ฑ)
bind(el, data): ์์el์data๋ฅผ ๋ถ์(Map์ ์ ์ฅ)getData(el): ๋์ค์ ๊ฐ์ ์์ ์ฐธ์กฐ๋ก ์ฆ์ ๊บผ๋(O(1))๐ซ ์ Map์ผ๋ก ํ ๊น?
- ๊ฐ์ฒด/ํจ์/DOM ๋ฑ ๋น๋ฌธ์์ด์ ํค๋ก ์์ ํ๊ฒ ์ฌ์ฉํ ์ ์์(๋ฌธ์์ด ํค ๊ฐ์ ๋ณํ ์์)
- ์์์ ์ง์ ์ปค์คํ ํ๋กํผํฐ๋ฅผ ๋ฌ์ง ์์๋ ๋จ โ ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ/DOM์ ์ค์ผ์ํค์ง ์์
- ์ฝ์ ยท์กฐํ๊ฐ ํ๊ท O(1), ์ํ ํ์ ์์ด ๋น ๋ฆ
๐ซ ์ฌ์ฉ ์์
// 1) ์ํ ์ฐ๊ฒฐ const el = document.querySelector('#btn'); bind(el, { clicked: 0, color: 'teal' }); // 2) ์ด๋ฒคํธ์์ ์ํ ์ ๋ฐ์ดํธ el.addEventListener('click', () => { const st = getData(el); st.clicked += 1; console.log(st.clicked); });๐ซ ์ค์ ํ
- GC(๊ฐ๋น์ง ์ปฌ๋ ์ )๊น์ง ์ ๊ฒฝ ์ด๋ค๋ฉด
WeakMap์ด ๋ ์ ํฉ
- DOM/๊ฐ์ฒด๊ฐ ์ด๋์์๋ ๋ ์ด์ ์ฐธ์กฐ๋์ง ์์ผ๋ฉด
WeakMap์ ์ํธ๋ฆฌ๋ฅผ ์๋์ผ๋ก ์ ๋ฆฌํจ(์ฝํ ์ฐธ์กฐ)- WeakMap: ํค๊ฐ ๋ฐ๋์ ๊ฐ์ฒด ๋๋ DOM์ด์ด์ผ ํ๊ณ , ๊ทธ ํค ๊ฐ์ฒด๊ฐ ์ด๋์์๋ ๋ ์ด์ ์ฐธ์กฐ๋์ง ์์ผ๋ฉด ํด๋น ์ํธ๋ฆฌ๊ฐ ์๋์ผ๋ก ๊ฐ๋น์ง ์ปฌ๋ ์ ๋๋ Map
โก๏ธ ์ปดํฌ๋ํธ ์์ฑ/ํ๊ดด๊ฐ ์ฆ๊ณ , DOM์ด ์ ๊ฑฐ๋๋ฉด ์๋ ์ ๋ฆฌ๋๊ธธ ์ํ ๋(๋ฉ๋ชจ๋ฆฌ ๋์ ๋ฐฉ์ง) ์ฌ์ฉํจ// ํค๊ฐ ๋ฐ๋์ ๊ฐ์ฒด/DOM์ด์ด์ผ ํจ. size/์ํ ๋ถ๊ฐ(์๋์ ) const dataByEl new WeakMap(); function bind(el, data) { dataByEl.set(el, data); } function getData(el) { return dataByEl.get(el); } function hasData(el) { return dataByEl.has(el); }- ํค๋ "์ฐธ์กฐ ๋์ผ์ฑ"
๋ชจ์์ด ๊ฐ์ ๋ค๋ฅธ ์์/๊ฐ์ฒด๋ฅผ ์๋ก ๋ง๋ค์ด๋ ๋ค๋ฅธ ํค์- ๋ฐ์ดํฐ ๊ตฌ์กฐ ์์
- ๋จ์ ๊ฐ:
{ opened: true },{ role: 'dialog' }- ๋ณตํฉ ์ํ:
{ timer, cleanup, options }- ์บ์:
{ measuredRect, lastComputedAt }- ์ง์ ํ๋กํผํฐ๋ก ๋ถ์ด๋ ๋ฐฉ์๊ณผ ๋น๊ต
โก๏ธ ์คํ์ผ/๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ถฉ๋ ์ํ, ํ์ ์์ ์ฑ/์บก์ํ ๋จ์ด์ง โ Map/WeakMap ๊ถ์ฅ// ์ํฐํจํด(๊ถ์ฅ X): DOM์ ์ค์ผ์ํค๊ณ ํค ์ถฉ๋ ์ํ el.__myData = { ... };
class BiMap {
#kv = new Map(); // key -> value
#vk = new Map(); // value -> key
// ์ ์ถ๊ฐ/๊ฐฑ์
set(k, v) { this.#kv.set(k, v); this.#vk.set(v, k); }
// key -> value
getByKey(k) { return this.#kv.get(k); }
// value -> key
getByValue(v) { return this.#vk.get(v); }
// key์ ๊ทธ์ ๋์ํ๋ value ๋ชจ๋ ์ ๊ฑฐ
deleteByKey(k) {
const v = this.#kv.get(k);
this.#kv.delete(k);
this.#vk.delete(v);
}
}๐ซ ์ญํ
- ๋ด๋ถ์
Map๋ ๊ฐ๋ฅผ ๋
#kv: key โ value#vk: value โ keyset(k, v)๋ ๋ ๋งต์ ๋์์ ๊ฐฑ์ ํด ๋ ๋ฐฉํฅ์ ์กฐํ๋ฅผ ๋ชจ๋ ๋น ๋ฅด๊ฒ ํจgetByKey,getByValue๋ก ์์ชฝ ๋ฐฉํฅ์ O(1)๋ก ์กฐํํจdeleteByKey๋ ํ์ชฝ์์ ์ง์ฐ๋ฉด ๋ฐ๋ํธ๋ ํจ๊ป ์ง์ ์ผ๊ด์ฑ์ ์ ์งํจ๐ซ ๋ฌธ๋ฒ/๋์์ธ ํฌ์ธํธ
#kv,#vk๋ ํ๋ผ์ด๋น ํ๋(ํด๋์ค ์ธ๋ถ์์ ์ ๊ทผ ๋ถ๊ฐ)Map์ ์ฝ์ ์์ ์ ์ง๋size,has๋ฑ ์ด์ ๊ทธ๋๋ก ํ์ฉ ๊ฐ๋ฅ- ์ฐธ์กฐ ๋์ผ์ฑ์ด ์ ์ฉ๋จ: ๊ฐ์ฒด/ํจ์๋ฅผ ํค, ๊ฐ์ผ๋ก ์ฐ๋ฉด ๊ฐ์ ๋ชจ์์ด์ด๋ ๊ฐ์ ์ฐธ์กฐ์ฌ์ผ ๊ฐ์ ๊ฒ์ผ๋ก ์ธ์ํจ
๐ซ ๋์ ์์
const bm = new BiMap(); bm.set('KR', 82); bm.set('US', 1); bm.getByKey('KR'); // 82 bm.getByValue(1); // 'US' bm.deleteByValue(1); // value ๊ธฐ์ค ์ญ์ ๋ ๊ฐ๋ฅ bm.hasKey('US'); // false๐ซ ์ธ์ ์ ์ฉํ ๊น?
- ์ฝ๋/๋ผ๋ฒจ ์ํธ ๋ณํ: ๊ตญ๊ฐ ์ฝ๋ โ ์ ํ ์ฝ๋, MIME โ ํ์ฅ์
๐ MIME: ํ์ผ/๋ฐ์ดํฐ์ ํ์(๋ฏธ๋์ด ํ์ )์ ํ์ค ๋ฌธ์์ด๋ก ๋ํ๋ด๋ ๊ท์น- ID โ ์ธ์คํด์ค ์ญ์ฐธ์กฐ: ๋ฆฌ์์ค ํ, ์์ผ/์ธ์ ๋งคํ
- ํ ํฐ โ ์ฌ์ฉ์ ๋งคํ ๋ฑ ์ญ์กฐํ๊ฐ ๋น๋ฒํ ์๋๋ฆฌ์ค
์ธ์ ์ฐ๋?
๋ฐฐ์ด ์ค๋ณต ์ ๊ฑฐ
// ์ซ์/๋ฌธ์์ด ์ค๋ณต ์ ๊ฑฐ
const arr = [1, 2, 2, 3, 3, 3];
const unique = [...new Set(arr)];
console.log(unique); // [1, 2, 3]
// NaN๋ ํ ๋ฒ๋ง ๋จ์ (Set์ SameValueZero ๊ท์น ์ ์ฉ)
console.log([...new Set([NaN, NaN])]); // [NaN]
// ๊ฐ์ฒด๋ '์ฐธ์กฐ ๋์ผ์ฑ' ๊ธฐ์ค
const a = { id: 1 }, b = { id: 1 };
console.log([...new Set([a, a, b])].length); // 2
// -> a๋ ๊ฐ์ ์ฐธ์กฐ 1๊ฐ๋ก ํฉ์ณ์ง๊ณ , b๋ ๋ณ๊ฐ
- ์ซ์/๋ฌธ์์ด ์ค๋ณต ์ ๊ฑฐ
new Set(arr)๋ก ๋ฐฐ์ด์ Set์ผ๋ก ๋ณํํ๋ฉด์ ์ค๋ณต์ ์๋ ์ ๊ฑฐํจ[...]์คํ๋ ๋๋ก ๋ค์ ๋ฐฐ์ด๋ก ํผ์นจ โ Set์ ์ดํฐ๋ฌ๋ธ์ด์ง๋ง ๋ฐฐ์ด ๋ฉ์๋๊ฐ ์๊ธฐ ๋๋ฌธ- ์๊ฐ ๋ณต์ก๋(ํ๊ท ): Set ๋น๋ O(n), ๋ฉ๋ชจ๋ฆฌ O(n)
NaN๋ ํ ๋ฒ๋ง ๋จ์
Set์ ๊ฐ ๋น๊ต์ SameValueZero๋ฅผ ์ฌ์ฉํจ โNaN์ ์๋ก ๊ฐ์ ๊ฐ์ผ๋ก ๋ด- ๊ทธ๋์
NaN์ ์ฌ๋ฌ ๋ฒ ๋ฃ์ด๋ ์ค๋ณต์ผ๋ก ํ๋จ๋์ด 1๊ฐ๋ง ์ ์ง๋จ- ๊ฐ์ฒด๋ '์ฐธ์กฐ ๋์ผ์ฑ' ๊ธฐ์ค
- ๊ฐ์ฒด๋ ๋ชจ์์ด ๊ฐ์๋ ๋ค๋ฅธ ์ฐธ์กฐ๋ฉด ๋ค๋ฅธ ๊ฐ์
a๋ ๊ฐ์ ๊ฐ์ฒด ์ฐธ์กฐ๋ฅผ ๋ ๋ฒ ๋ฃ์์ผ๋ฏ๋ก 1๊ฐ๋ก ํฉ์ณ์งb๋a์ ๋ค๋ฅธ ๊ฐ์ฒด๋ผ ๋ณ๋ ์์๋ก ๋จ์ ์ด 2๊ฐ๊ฐ ๋จ
๋ฐฉ๋ฌธ ์ฒดํฌ/ํ ๊ธ
// ์ ํ/์ฆ๊ฒจ์ฐพ๊ธฐ/๋ฐฉ๋ฌธ ์ฌ๋ถ ํ ๊ธ
const selected = new Set();
function toggle(id) {
if (selected.has(id)) selected.delete(id);
else selected.add(id);
}
toggle('p1'); // ์ ํ
toggle('p2'); // ์ ํ
toggle('p1'); // ํด์
console.log([...selected]); // ['p2']
// "์ฒ์ ๋ฐฉ๋ฌธ์ธ๊ฐ?" ๋ฐฉ๋ฌธ ์ฒดํฌ
const seen = new Set();
function isFirstVisit(key) {
if (seen.has(key)) return false; // ์ด๋ฏธ ๋ณธ ์ ์์
seen.add(key); // ์ฒ์ ๋ณด๋ฉด ๋ฑ๋ก
return true; // ์ฒ์ ๋ฐฉ๋ฌธ
}
console.log(isFirstVisit('A')); // true
console.log(isFirstVisit('A')); // false
- ์ ํ/์ฆ๊ฒจ์ฐพ๊ธฐ ํ ๊ธ ์์
selected๋ ์ ํ๋ ํญ๋ชฉ๋ค์ ์งํฉ์toggle(id)๋ ๊ฐ์ ID๋ฅผ ์์ผ๋ฉด ์ถ๊ฐ, ์์ผ๋ฉด ์ ๊ฑฐํ์ฌ ํ ๊ธํจselected.has(id)๋ก ํฌํจ ์ฌ๋ถ๋ฅผ O(1)๋ก ๊ฒ์ฌํจ- "์ฒ์ ๋ฐฉ๋ฌธ์ธ๊ฐ?" ๋ฐฉ๋ฌธ ์ฒดํฌ
- ์ด๋ค
key(์: ์ฌ์ฉ์ ID, ํ์ด์ง ID)๋ฅผ ํ ๋ฒ์ด๋ผ๋ ๋ดค๋์ง ๊ธฐ๋กํจ- ์ฒ์์ด๋ฉด
true, ์ดํ์๋ ํญ์false
์ํ์ ์งํฉ ์ฐ์ฐ(ํฉ/๊ต/์ฐจ/๋์นญ์ฐจ) ๊ตฌํ
const A = new Set([1, 2, 3]);
const B = new Set([3, 4, 5]);
// ํฉ์งํฉ: A โช B
const union = new Set([...A, ...B]);
console.log([...union]); // [1, 2, 3, 4, 5]
// ๊ต์งํฉ: A โฉ B
const intersection = new Set([...A].filter(x => B.has(x)));
console.log([...intersection]); // [3]
// ์ฐจ์งํฉ: A \ B (A์๋ ์๊ณ B์๋ ์๋ ์์)
const difference = new Set([...A].filter(x => !B.has(x)));
console.log([...difference]); // [1, 2]
// ๋์นญ์ฐจ: (A \ B) โช (B \ A)
const symmetricDiff = new Set([
...[...A].filter(x => !B.has(x)),
...[...B].filter(x => !A.has(x)),
]);
console.log([...symmetricDiff]); // [1, 2, 4, 5]
- ํฉ์งํฉ (A โช B)
...A,...B๋ก ๋ ์งํฉ์ ํผ์ณ์ ํ๋์ ๋ฐฐ์ด๋ก ๋ง๋ ๋คnew Set(...)์ ๋ฃ์ด ์ค๋ณต์ ์ ๊ฑฐํจ- ์๊ฐ๋ณต์ก๋(ํ๊ท ): O(|A| + |B|)
- ๊ต์งํฉ (A โฉ B)
A์ ์์ ์คB์ ์กด์ฌํ๋ ๊ฒ๋ง ๊ฑธ๋ฌ์Set์ผ๋ก ์์ฑํจ- ํต์ฌ์
B.has(x)๊ฐ ํ๊ท O(1)์ด๋ผ ์ ์ฒด ์๊ฐ๋ณต์ก๋๋ O(|A|)- ์ฐจ์งํฉ (A \ B)
A์์B์ ์๋ ๊ฒ๋ง ๋จ๊น- ์๊ฐ๋ณต์ก๋(ํ๊ท ): O(|A|)
- ๋์นญ์ฐจ (A โณ B)
- ์์ชฝ ์ฐจ์งํฉ์ ํฉ์ณ์ Set์ ๋ฃ์ด ์ค๋ณต ์ ๊ฑฐ
- ์๊ฐ๋ณต์ก๋(ํ๊ท ): O(|A| + |B|)
set.sizeset.has(value)set.add(value) (์ด๋ฏธ ์์ผ๋ฉด ๋ณํ ์์)set.delete(value), set.clear()for (const v of set), set.forEach(v => ...)NaN๋ ๋์ผ ์ทจ๊ธ)๋ฐฐ์ด๊ณผ์ ์ํธ ๋ณํ
const arr = [1, 1, 2, 3];
const unique = [...new Set(arr)]; // [1, 2, 3]
const s2 = new Set(arr);
const backToArray = Array.from(s2);
๐
Array.from1. ์ ์
- ์ดํฐ๋ฌ๋ธ(iterable) ๋๋ ์ ์ฌ ๋ฐฐ์ด(array-like)์ ์ง์ง ๋ฐฐ์ด๋ก ๋ฐํํจ
- ์ดํฐ๋ฌ๋ธ:
Set,Map, ๋ฌธ์์ด, ์ ๋๋ ์ดํฐ ๋ฑSymbol.iterator์ด ์๋ ๊ฒ- ์ ์ฌ ๋ฐฐ์ด:
length์ ์ธ๋ฑ์ค ํ๋กํผํฐ๊ฐ ์๋ ๊ฐ์ฒด(์:arguments, DOMNodeList๋ฑ)2. ์๊ทธ๋์ฒ
Array.from(source, mapFn?, thisArg?)
source: ์ดํฐ๋ฌ๋ธ/์ ์ฌ ๋ฐฐ์ดmapFn(value, index): ์์ฑํ๋ฉด์ ๋งคํ(์ฑ๋ฅยท๋ฉ๋ชจ๋ฆฌ ์ ๋ฆฌ)thisArg:mapFn๋ด๋ถ์this3. ์์ ๋ชจ์
1) Set/Map โ Array
const s = new Set([1, 2, 3]); Array.from(s); // [1, 2, 3] const m = new Map([['a', 1], ['b', 2]]); Array.from(m); // [['a', 1], ['b', 2]] Array.from(m, ([k, v]) => k); // ['a', 'b'] (ํค๋ง)2) ์ ์ฌ ๋ฐฐ์ด โ Array
function f() { const args = Array.from(arguments); // ์ง์ง ๋ฐฐ์ด // [...arguments]๋ ์ผ๋ถ ํ๊ฒฝ์์ ์คํจ(์ดํฐ๋ฌ๋ธ์ด ์๋ ์ ์์) }const nodeList = document.querySelectorAll('div'); // ์ ์ฌ ๋ฐฐ์ด + iterable Array.from(nodeList, el => el.textContent.trim());3) ๋ฌธ์์ด โ ๋ฌธ์ ๋ฐฐ์ด
Array.from('hello'); // ['h', 'e', 'l', 'l', 'o']4) ์์ฑ + ๋งคํ ํ ๋ฒ์ (์ฑ๋ฅ ์ด์ )
Array.from({ length: 5 }, (_, i) => i * i); // [0, 1, 4, 9, 16]4. ์คํ๋ ๋(
...)์ ์ฐจ์ด
์ํฉ Array.from์คํ๋ ๋( [...src])Set/Map/๋ฌธ์์ด ๊ฐ๋ฅ ๊ฐ๋ฅ ์ ์ฌ ๋ฐฐ์ด(iterator ์์) ๊ฐ๋ฅ ๋ถ๊ฐ๋ฅ(TypeError) ์์ฑ ์ ๋งคํ mapFn์ ๊ณต๋ง๋ค๊ณ ๋์ mapํ ๋ฒ ๋์ ๋์ฝ๋(๋ฌธ์ ๋จ์) ๋ฌธ์์ด ์ดํฐ๋ ์ดํฐ๋ก OK ๋ฌธ์์ด ์ดํฐ๋ ์ดํฐ๋ก OK
- ์ ์ฌ ๋ฐฐ์ด์ธ๋ฐ iterator๊ฐ ์๋ ๊ฐ์ฒด ์์
const arrayLike = { 0: 'a', 1: 'b', length: 2 }; // iterator ์์ Array.from(arrayLike); // ['a', 'b'] โ ๊ฐ๋ฅ (length/์ธ๋ฑ์ค๋ฅผ ์ฝ์ด ๋ฐฐ์ด ์์ฑ) [...arrayLike]; // โ TypeError: arrayLike is not iterable5. ํฌ์ ๋ฐฐ์ด(sparse) ์ฒ๋ฆฌ
Array.from({ length: 3 }); // [undefined, undefined, undefined]
Array.from์ ์ธ๋ฑ์ค๋ฅผ 0 ~ length-1๋ก ์ํํ๋ฉฐ ๋น ์นธ๋ ์ฑ์undefined๊ฐ ๋จ- ๋ฐ๋ฉด ๋ฆฌํฐ๋ด๋ก ๋ง๋ ํฌ์ ๋ฐฐ์ด(
[ , , ])์ ๊ตฌ๋ฉ์ด ๋จ์ ์ ์์- ์ผ๊ด์ฑ์ด ํ์ํ๋ฉด
Array.from์ด ์์ ํจ6. ์์ ๋ณต์ฌ (Shallow)
๊ฐ์ฒด ์์๋ ์ฐธ์กฐ๋ง ๋ณต์ฌ๋จ
const a = [{ x: 1 }]; const b = Array.from(a); b[0].x = 2; console.log(a[0].x); // 2 (๊ฐ์ ๊ฐ์ฒด ์ฐธ์กฐ)
const union = (A, B) => new Set([...A, ...B]);
const intersection = (A, B) => new Set([...A].filter(x => B.has(x)));
const difference = (A, B) => new Set([...A].filter(x => !B.has(x)));
const symmetricDiff = (A, B) => new Set([...difference(A, B), ...difference(B, A)]);์ค๋ณต ์ ๊ฑฐ & ์ ๋ํฌ ๋ณด์ฅ
const users = ["kim", "lee", "kim"];
const uniqueUsers = [...new Set(users)]; // ["kim", "lee"]
๐ซ ๋จ๊ณ๋ณ ๋์
new Set(users)
- ๋ฐฐ์ด์ Set์ผ๋ก ๋ฐ๊พธ๋ ์๊ฐ ์ค๋ณต ์์๊ฐ ์๋ ์ ๊ฑฐ๋จ
- Set์ ๊ฐ ๋น๊ต์ SameValueZero ๊ท์น์ ์จ์
NaN๋ ํ๋๋ก ์ทจ๊ธํ๊ณ , ์ฝ์ ์์๋ฅผ ์ ์งํจ[...set]
- Set(์ดํฐ๋ฌ๋ธ)์ ๋ฐฐ์ด๋ก ๋ค์ ํผ์นจ
- ๊ฒฐ๊ณผ:
["kim", "lee"](์ฒซ ๋ฑ์ฅ ์์ ์ ์ง)๐ซ ์ Set์ ์ธ๊น?
- ๊ฐ๊ฒฐ + ๋น ๋ฆ: ํ๊ท O(n)์ผ๋ก ํ ๋ฒ์ ์ฒ๋ฆฌํจ
- ์ค๋ณต ์๋ ๋ฐฉ์ง: ๊ฐ์ ๊ฐ์ด ์ฌ๋ฌ ๋ฒ ์๋ ํ๋๋ง ์ ์งํจ
- ์์ ๋ณด์กด: ์๋ ๋ฐฐ์ด์์ ์ต์ด ๋ฑ์ฅ ์์๊ฐ ๊ฒฐ๊ณผ์๋ ๋ฐ์๋จ
๋ฐฉ๋ฌธ/์ ํ ์ํ ๊ด๋ฆฌ (ํ ๊ธ)
const selected = new Set();
function toggle(id) {
if (selected.has(id)) selected.delete(id);
else selected.add(id);
}
๐ซ ์ฝ๋ ์ค๋ช
selected: ํ์ฌ ์ ํ๋์ด ์๋ ํญ๋ชฉ๋ค์ ์งํฉtoggle(id)
- ์ด๋ฏธ ์์ผ๋ฉด(
has) โ ์ ๊ฑฐ(delete) = ํด์ - ์์ผ๋ฉด โ ์ถ๊ฐ(
add) = ์ ํ๐ซ ์ฌ์ฉ ์ (๋์ ํ์ธ)
toggle('p1'); // ์ ํ: {'p1'} toggle('p2'); // ์ ํ: {'p1', 'p2'} toggle('p1'); // ํด์ : {'p2'} console.log([...selected]); // ['p2']
ํํฐ๋ง ๋ณด์กฐ (ํ์ดํธ๋ฆฌ์คํธ/๋ธ๋๋ฆฌ์คํธ)
const allow = new Set(["/home", "/about"]);
const filtered = routes.filter(r => allow.has(r.path));
๐ซ ์ฝ๋ ์ค๋ช
allow: ์ ๊ทผ/๋ ธ์ถ์ ํ์ฉํ ๊ฒฝ๋ก๋ค์ ์งํฉroutes:{ path: string, ...}ํํ์ ๋ผ์ฐํธ ๋ฐฐ์ด์ด๋ผ๊ณ ๊ฐ์ filter: ๊ฐ ๋ผ์ฐํธr์r.path๊ฐallow์ ์์ผ๋ฉด(has) ๋จ๊ธฐ๊ณ , ์์ผ๋ฉด ๋ฒ๋ฆผ- ๊ฒฐ๊ณผ
filtered:"/home",/"about"๋ง ํฌํจ๋ ๋ผ์ฐํธ ๋ฐฐ์ด๐ซ ์๊ฐ ๋ณต์ก๋
- ํํฐ๋ง ์ ์ฒด: O(|routes|) (๊ฐ ์์๋น
hasํ ๋ฒ)- ๋ฐฐ์ด์
includes๋ฅผ ์ฐ๋ฉด O(|routes|ร|allow|)๋ก ์ปค์ง ์ ์์
๊ต์งํฉ ๊ธฐ๋ฐ์ ๋น ๋ฅธ ๊ต์ฐจ ์ฒดํฌ
function hasAnyOverlap(aArr, bArr) {
const B = new Set(bArr);
return aArr.some(x => B.has(x));
}
๐ซ ์ฝ๋ ์ค๋ช
bArr๋ฅผSet์ผ๋ก ๋ง๋ค์ด ํฌํจ ๊ฒ์ฌ๋ฅผ O(1)๋ก ๋น ๋ฅด๊ฒ ํ๊ณ ,aArr๋ฅผ ์ํํ๋ฉด์ ํ๋๋ผ๋B์ ์์ผ๋ฉดtrue๋ฅผ ์ฆ์ ๋ฐํ(์กฐ๊ธฐ ์ข ๋ฃ)ํจ- ๋๊น์ง ์์ผ๋ฉด
false๐ซ ์๊ฐ ๋ณต์ก๋
B.has(x)๋ ํ๊ท O(1)- ์ ์ฒด ๋ณต์ก๋๋ O(|aArr|+|bArr|)
- ๋ฐฐ์ด์
includes๋ฅผ ์ฐ๋ฉด O(|aArr|ร|bArr|)๊ฐ ๋์ด ์ปค์ง์๋ก ๋๋ ค์ง๐ซ ๋์ ์์
hasAnyOverlap([1, 2, 3], [4, 5]); // false hasAnyOverlap([1, 2, 3], [3, 4, 5]); // true hasAnyOverlap(['a', 'b'], ['B']); // false (๋์๋ฌธ์ ๊ตฌ๋ถ)
| ์ํฉ | ์ถ์ฒ |
|---|---|
ํค๋ก ๊ฐ์ฒด/ํจ์/NaN ๋ฑ ๋น๋ฌธ์์ด์ ์จ์ผ ํจ | Map |
| ํค์ ์ฝ์ ์์ ์ ์ง + ๋น๋ฒํ ์ํ | Map |
| ํค ๊ฐ์ ์์ฃผ ํ์ธ | Map (size) |
| JSON ์ง๋ ฌํ ๊ฐ๋จ/์ ์ ํค ๊ตฌ์กฐ | Object |
| ์ค๋ณต ์ ๊ฑฐ/์งํฉ ์ฐ์ฐ์ด ํต์ฌ | Set |
| ์ธ๋ฑ์ค ์ ๊ทผ/์ ๋ ฌ/์ฌ๋ผ์ด์ฑ ๋ฑ ๋ฐฐ์ด ๊ธฐ๋ฅ | Array |