โ† ๋ชฉ๋ก์œผ๋กœ
AI-assisted content
JavaScript Map vs Object Deep Dive

JavaScript์—์„œ ํ‚ค-๊ฐ’ ์Œ์„ ์ €์žฅํ•  ๋•Œ, ๋Œ€๋ถ€๋ถ„ {} ๊ฐ์ฒด๋ฅผ ์”๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ES6์—์„œ Map์ด ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์™œ Object๊ฐ€ ์žˆ๋Š”๋ฐ Map์„ ๋”ฐ๋กœ ๋งŒ๋“ค์—ˆ์„๊นŒ์š”? "๋‘˜ ๋‹ค ํ‚ค-๊ฐ’ ์ €์žฅ์†Œ ์•„๋‹ˆ์•ผ?"๋ผ๊ณ  ์ƒ๊ฐํ•˜๊ธฐ ์‰ฝ์ง€๋งŒ, ๋‚ด๋ถ€ ๊ตฌ์กฐ๋ถ€ํ„ฐ ์šฉ๋„๊นŒ์ง€ ๊ทผ๋ณธ์ ์œผ๋กœ ๋‹ค๋ฆ…๋‹ˆ๋‹ค.

Object์˜ ๋ณธ์งˆ: ํ”„๋กœํผํ‹ฐ ์ปจํ…Œ์ด๋„ˆ

Object๋Š” ์›๋ž˜ ํ‚ค-๊ฐ’ ์ €์žฅ์†Œ๋กœ ์„ค๊ณ„๋œ ๊ฒƒ์ด ์•„๋‹™๋‹ˆ๋‹ค. ํ”„๋กœํผํ‹ฐ์˜ ์ง‘ํ•ฉ์ž…๋‹ˆ๋‹ค. ๋ฉ”์„œ๋“œ๋ฅผ ๋‹ด๊ณ , ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์„ ํ†ตํ•ด ์ƒ์†์„ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด ๋ณธ๋ž˜ ๋ชฉ์ ์ž…๋‹ˆ๋‹ค.

const user = {
  name: 'Kim',
  greet() {
    return `Hello, ${this.name}`;
  },
};

// user๋Š” "๋ฐ์ดํ„ฐ ์ €์žฅ์†Œ"๊ฐ€ ์•„๋‹ˆ๋ผ "์—”ํ‹ฐํ‹ฐ"์ž…๋‹ˆ๋‹ค.
// ํ”„๋กœํผํ‹ฐ(name)์™€ ํ–‰์œ„(greet)๋ฅผ ํ•จ๊ป˜ ๊ฐ€์ง‘๋‹ˆ๋‹ค.

์ด ๊ตฌ์กฐ๋ฅผ ํ‚ค-๊ฐ’ ์ €์žฅ์†Œ๋กœ ์“ฐ๋ฉด ์—ฌ๋Ÿฌ ๋ฌธ์ œ๊ฐ€ ์ƒ๊น๋‹ˆ๋‹ค.

ํ”„๋กœํ† ํƒ€์ž… ์˜ค์—ผ

const map = {};
map['toString'] = 'hello';

// ์˜๋„: 'toString'์ด๋ผ๋Š” ํ‚ค์— 'hello'๋ฅผ ์ €์žฅ
// ์‹ค์ œ: Object.prototype.toString์„ ๋ฎ์–ด์”€
typeof map.toString; // 'string' (ํ•จ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ๋ฌธ์ž์—ด)

Object.create(null)๋กœ ํ”„๋กœํ† ํƒ€์ž… ์—†๋Š” ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค๋ฉด ์ด ๋ฌธ์ œ๋ฅผ ํ”ผํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๊ทธ๊ฑด Object์˜ ํ•ต์‹ฌ ๊ธฐ๋Šฅ(ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ)์„ ํฌ๊ธฐํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ‚ค-๊ฐ’ ์ €์žฅ์†Œ๋กœ ์“ฐ๊ธฐ ์œ„ํ•ด Object์˜ ๋ณธ์งˆ์„ ๋ถ€์ •ํ•˜๋Š” ์…ˆ์ž…๋‹ˆ๋‹ค.

ํ‚ค ํƒ€์ž… ์ œํ•œ

Object์˜ ํ‚ค๋Š” ๋ฌธ์ž์—ด ๋˜๋Š” Symbol๋งŒ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

const obj = {};
const key1 = { id: 1 };
const key2 = { id: 2 };

obj[key1] = 'first';
obj[key2] = 'second';

console.log(obj[key1]); // 'second' โ† 'first'๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค
console.log(Object.keys(obj)); // ['[object Object]']
// key1๊ณผ key2 ๋ชจ๋‘ '[object Object]'๋กœ ๋ณ€ํ™˜๋˜์–ด ๊ฐ™์€ ํ‚ค๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

์ˆซ์ž๋ฅผ ํ‚ค๋กœ ์จ๋„ ๋‚ด๋ถ€์ ์œผ๋กœ ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค.

const obj = {};
obj[1] = 'one';
obj['1'] = 'one string';

console.log(obj[1]); // 'one string'
// ์ˆซ์ž 1๊ณผ ๋ฌธ์ž์—ด '1'์ด ๊ฐ™์€ ํ‚ค์ž…๋‹ˆ๋‹ค.

Map์˜ ์„ค๊ณ„: ์ˆœ์ˆ˜ํ•œ ํ‚ค-๊ฐ’ ์ €์žฅ์†Œ

Map์€ ์ฒ˜์Œ๋ถ€ํ„ฐ ํ‚ค-๊ฐ’ ์ €์žฅ์†Œ๋กœ ์„ค๊ณ„๋˜์—ˆ์Šต๋‹ˆ๋‹ค. Object์˜ ํ‚ค-๊ฐ’ ์šฉ๋„ ํ•œ๊ณ„๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ES6์—์„œ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

const map = new Map();

// ์–ด๋–ค ํƒ€์ž…์ด๋“  ํ‚ค๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
map.set(1, 'number key');
map.set('1', 'string key');
map.set(true, 'boolean key');
map.set(null, 'null key');
map.set({ id: 1 }, 'object key');
map.set(document.body, 'DOM element key');

console.log(map.get(1));   // 'number key'
console.log(map.get('1')); // 'string key' โ€” ๊ตฌ๋ถ„๋ฉ๋‹ˆ๋‹ค

Map์˜ ํ‚ค ๋น„๊ต๋Š” SameValueZero ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ===์™€ ๊ฑฐ์˜ ๊ฐ™์ง€๋งŒ, NaN === NaN์„ true๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

const map = new Map();

map.set(NaN, 'not a number');
console.log(map.get(NaN)); // 'not a number'
// === ์—์„œ๋Š” NaN !== NaN์ด์ง€๋งŒ, Map์—์„œ๋Š” ๊ฐ™์€ ํ‚ค๋กœ ์ทจ๊ธ‰ํ•ฉ๋‹ˆ๋‹ค.

map.set(0, 'zero');
map.set(-0, 'negative zero');
console.log(map.get(0)); // 'negative zero'
// 0๊ณผ -0๋„ ๊ฐ™์€ ํ‚ค๋กœ ์ทจ๊ธ‰ํ•ฉ๋‹ˆ๋‹ค.

๋‹จ, ๊ฐ์ฒด ํ‚ค๋Š” ์ฐธ์กฐ ๋™์ผ์„ฑ์œผ๋กœ ๋น„๊ตํ•ฉ๋‹ˆ๋‹ค.

const map = new Map();

map.set({ id: 1 }, 'first');
console.log(map.get({ id: 1 })); // undefined
// ๋‚ด์šฉ์ด ๊ฐ™์•„๋„ ๋‹ค๋ฅธ ์ฐธ์กฐ์ด๋ฏ€๋กœ ๋‹ค๋ฅธ ํ‚ค์ž…๋‹ˆ๋‹ค.

const key = { id: 1 };
map.set(key, 'found');
console.log(map.get(key)); // 'found'
// ๊ฐ™์€ ์ฐธ์กฐ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

ํ•ต์‹ฌ ์ฐจ์ด ๋น„๊ต

ObjectMap
ํ‚ค ํƒ€์ž…๋ฌธ์ž์—ด, Symbol๋ชจ๋“  ๊ฐ’ (๊ฐ์ฒด, ํ•จ์ˆ˜, ์›์‹œ๊ฐ’)
ํ‚ค ์ˆœ์„œ์ •์ˆ˜ ํ‚ค โ†’ ๋ฌธ์ž์—ด ํ‚ค(์‚ฝ์ž…์ˆœ) โ†’ Symbol ํ‚คํ•ญ์ƒ ์‚ฝ์ž… ์ˆœ์„œ ๋ณด์žฅ
ํฌ๊ธฐ ํ™•์ธObject.keys(obj).length (O(n))map.size (O(1))
๋ฐ˜๋ณตObject.keys() / for...infor...of / forEach (์ง์ ‘ iterable)
ํ”„๋กœํ† ํƒ€์ž…์žˆ์Œ (ํ‚ค ์ถฉ๋Œ ๊ฐ€๋Šฅ)์—†์Œ (์ˆœ์ˆ˜ ์ €์žฅ์†Œ)
์ง๋ ฌํ™”JSON.stringify() ๋„ค์ดํ‹ฐ๋ธŒ ์ง€์›์ง์ ‘ ๋ณ€ํ™˜ ํ•„์š”
์„ฑ๋Šฅ (๋นˆ๋ฒˆํ•œ ์ถ”๊ฐ€/์‚ญ์ œ)๋А๋ฆผ๋น ๋ฆ„

์‚ฝ์ž… ์ˆœ์„œ์™€ ํ‚ค ์ •๋ ฌ

Object์˜ ํ‚ค ์ˆœ์„œ๋Š” ์ง๊ด€์ ์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ECMAScript ์ŠคํŽ™์—์„œ ์ •์˜๋œ ๊ทœ์น™์ด ์žˆ์Šต๋‹ˆ๋‹ค.

const obj = {};
obj['b'] = 2;
obj['1'] = 1;
obj['a'] = 3;
obj['2'] = 4;
obj[Symbol('s')] = 5;

console.log(Object.keys(obj));
// ['1', '2', 'b', 'a']
// ์ •์ˆ˜ ํ‚ค๊ฐ€ ๋จผ์ €(์˜ค๋ฆ„์ฐจ์ˆœ) โ†’ ๋ฌธ์ž์—ด ํ‚ค(์‚ฝ์ž…์ˆœ) โ†’ Symbol(Object.keys์—๋Š” ์•ˆ ๋‚˜์˜ด)

Map์€ ๋‹จ์ˆœํ•ฉ๋‹ˆ๋‹ค. ํ•ญ์ƒ ์‚ฝ์ž… ์ˆœ์„œ์ž…๋‹ˆ๋‹ค.

const map = new Map();
map.set('b', 2);
map.set(1, 1);
map.set('a', 3);
map.set(2, 4);

console.log([...map.keys()]); // ['b', 1, 'a', 2] โ€” ๋„ฃ์€ ์ˆœ์„œ ๊ทธ๋Œ€๋กœ

์ˆœํšŒ(Iteration) ์ฐจ์ด

Object๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ iterable์ด ์•„๋‹™๋‹ˆ๋‹ค. for...of๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

const obj = { a: 1, b: 2, c: 3 };

// โŒ TypeError: obj is not iterable
for (const [key, value] of obj) { }

// Object๋ฅผ ์ˆœํšŒํ•˜๋ ค๋ฉด ๋ณ€ํ™˜์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค
for (const [key, value] of Object.entries(obj)) {
  console.log(key, value);
}

// ๋˜๋Š” for...in (ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์˜ ํ”„๋กœํผํ‹ฐ๋„ ํฌํ•จ๋  ์ˆ˜ ์žˆ์Œ)
for (const key in obj) {
  if (obj.hasOwnProperty(key)) {
    console.log(key, obj[key]);
  }
}

Map์€ iterable protocol์„ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ์–ด์„œ ์ง์ ‘ ์ˆœํšŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const map = new Map([['a', 1], ['b', 2], ['c', 3]]);

// โœ… ๋ฐ”๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
for (const [key, value] of map) {
  console.log(key, value);
}

// ๊ตฌ์กฐ ๋ถ„ํ•ด, ์Šคํ”„๋ ˆ๋“œ, Array.from ๋ชจ๋‘ ๊ฐ€๋Šฅ
const entries = [...map];           // [['a', 1], ['b', 2], ['c', 3]]
const keys = [...map.keys()];       // ['a', 'b', 'c']
const values = [...map.values()];   // [1, 2, 3]

// forEach๋„ ์ง€์› (์ฝœ๋ฐฑ ์ธ์ž ์ˆœ์„œ ์ฃผ์˜: value, key)
map.forEach((value, key) => {
  console.log(key, value);
});

์„ฑ๋Šฅ: ์–ธ์ œ ์ฐจ์ด๊ฐ€ ๋‚˜๋Š”๊ฐ€

V8 ์—”์ง„์€ Object๋ฅผ Hidden Class(๋‚ด๋ถ€์ ์œผ๋กœ Shape ๋˜๋Š” Structure๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค)๋กœ ์ตœ์ ํ™”ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ™์€ ๊ตฌ์กฐ์˜ ๊ฐ์ฒด๋ฅผ ๋ฐ˜๋ณต ์ƒ์„ฑํ•˜๋ฉด ๊ฐ™์€ Hidden Class๋ฅผ ๊ณต์œ ํ•˜๋ฉฐ, ํ”„๋กœํผํ‹ฐ ์ ‘๊ทผ์ด ์ •์  ์˜คํ”„์…‹ ๊ณ„์‚ฐ์œผ๋กœ ์ด๋ฃจ์–ด์ ธ ๋งค์šฐ ๋น ๋ฆ…๋‹ˆ๋‹ค.

// V8์ด Hidden Class๋ฅผ ๋งŒ๋“ค์–ด ์ตœ์ ํ™”ํ•˜๋Š” ํŒจํ„ด
function createUser(name, age) {
  return { name, age }; // ํ•ญ์ƒ ๊ฐ™์€ ๊ตฌ์กฐ โ†’ ๊ฐ™์€ Hidden Class
}

// ์ด๋ ‡๊ฒŒ ์“ฐ๋ฉด ์ •์  ์ปดํŒŒ์ผ ์–ธ์–ด ์ˆ˜์ค€์˜ ํ”„๋กœํผํ‹ฐ ์ ‘๊ทผ ์†๋„
const user = createUser('Kim', 30);
console.log(user.name); // Hidden Class ๋•๋ถ„์— ์˜คํ”„์…‹ ๊ณ„์‚ฐ์œผ๋กœ ์ฆ‰์‹œ ์ ‘๊ทผ

ํ•˜์ง€๋งŒ Object๋ฅผ ํ‚ค-๊ฐ’ ์ €์žฅ์†Œ์ฒ˜๋Ÿผ ๋™์ ์œผ๋กœ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ถ”๊ฐ€/์‚ญ์ œํ•˜๋ฉด Hidden Class ์ตœ์ ํ™”๊ฐ€ ๊นจ์ง‘๋‹ˆ๋‹ค. V8์€ ์ด๋Ÿฐ Object๋ฅผ "dictionary mode"๋กœ ์ „ํ™˜ํ•˜๋Š”๋ฐ, ์ด ๋ชจ๋“œ์—์„œ๋Š” ํ•ด์‹œ ํ…Œ์ด๋ธ”์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

const cache = {};

// ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ณ„์† ์ถ”๊ฐ€/์‚ญ์ œํ•˜๋ฉด dictionary mode๋กœ ์ „ํ™˜
for (let i = 0; i < 10000; i++) {
  cache[`key_${i}`] = i;
}

// delete ์—ฐ์‚ฐ์€ Hidden Class๋ฅผ ๊นจ๋œจ๋ฆฌ๋Š” ๋Œ€ํ‘œ์ ์ธ ํŒจํ„ด
delete cache['key_500'];

Map์€ ์ฒ˜์Œ๋ถ€ํ„ฐ ํ•ด์‹œ ํ…Œ์ด๋ธ”๋กœ ๊ตฌํ˜„๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋™์  ์ถ”๊ฐ€/์‚ญ์ œ๊ฐ€ ๋นˆ๋ฒˆํ•œ ๊ฒฝ์šฐ Map์ด ๋” ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค.

๋ฒค์น˜๋งˆํฌ ๊ฒฝํ–ฅ

์‹ค์ œ ์„ฑ๋Šฅ์€ ์—”์ง„, ๋ฐ์ดํ„ฐ ํฌ๊ธฐ, ์ ‘๊ทผ ํŒจํ„ด์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง€์ง€๋งŒ, ์ผ๋ฐ˜์ ์ธ ๊ฒฝํ–ฅ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์—ฐ์‚ฐObjectMap
๊ณ ์ • ๊ตฌ์กฐ์˜ ํ”„๋กœํผํ‹ฐ ์ฝ๊ธฐ๋น ๋ฆ„ (Hidden Class ์ตœ์ ํ™”)๋ณดํ†ต
๋™์  ํ‚ค ์ถ”๊ฐ€๋А๋ ค์งˆ ์ˆ˜ ์žˆ์Œ (dictionary mode ์ „ํ™˜)๋น ๋ฆ„
ํ‚ค ์‚ญ์ œ๋А๋ฆผ (delete๊ฐ€ Hidden Class ํŒŒ๊ดด)๋น ๋ฆ„
ํฌ๊ธฐ ํ™•์ธ๋А๋ฆผ (Object.keys().length, O(n))๋น ๋ฆ„ (size, O(1))
ํ‚ค ์กด์žฌ ํ™•์ธ'key' in obj ๋˜๋Š” hasOwnPropertymap.has(key) (๋‘˜ ๋‹ค ๋น ๋ฆ„)

delete ์—ฐ์‚ฐ์ด Object์—์„œ ํŠนํžˆ ๋น„์šฉ์ด ํฐ ์ด์œ ๋Š”, Hidden Class ์ „ํ™˜(transition)์„ ๋ฐœ์ƒ์‹œํ‚ค๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. V8์€ ํ”„๋กœํผํ‹ฐ๊ฐ€ ์‚ญ์ œ๋˜๋ฉด ์ƒˆ๋กœ์šด Hidden Class๋ฅผ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜ dictionary mode๋กœ ์ „ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด Map์˜ delete()๋Š” ํ•ด์‹œ ํ…Œ์ด๋ธ”์—์„œ ์—”ํŠธ๋ฆฌ๋ฅผ ์ œ๊ฑฐํ•˜๋Š” ๋‹จ์ˆœํ•œ ์—ฐ์‚ฐ์ž…๋‹ˆ๋‹ค.

๋ฉ”๋ชจ๋ฆฌ: Map์ด ๋” ํšจ์œจ์ ์ธ ๊ฒฝ์šฐ

๋งŽ์€ ํ‚ค-๊ฐ’ ์Œ์„ ์ €์žฅํ•  ๋•Œ, Map์ด Object๋ณด๋‹ค ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ ๊ฒŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝํ–ฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค. Object๋Š” Hidden Class ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ, ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ, ํ”„๋กœํผํ‹ฐ ๋””์Šคํฌ๋ฆฝํ„ฐ(writable, enumerable, configurable) ๋“ฑ ๋ถ€๊ฐ€ ์ •๋ณด๋ฅผ ์œ ์ง€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. Map์€ ํ‚ค-๊ฐ’ ์Œ๋งŒ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

V8 ๋ธ”๋กœ๊ทธ์— ๋”ฐ๋ฅด๋ฉด, ์ˆ˜์ฒœ ๊ฐœ ์ด์ƒ์˜ ์—”ํŠธ๋ฆฌ๋ฅผ ๊ฐ€์ง„ ์ปฌ๋ ‰์…˜์—์„œ Map์˜ ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ์ด Object๋ฅผ ํฌ๊ฒŒ ์•ž์„ญ๋‹ˆ๋‹ค.

JSON๊ณผ์˜ ๊ด€๊ณ„

Object์˜ ๊ฐ€์žฅ ํฐ ์‹ค์šฉ์  ์žฅ์ ์€ JSON๊ณผ์˜ 1:1 ํ˜ธํ™˜์ž…๋‹ˆ๋‹ค.

const obj = { name: 'Kim', age: 30, active: true };
const json = JSON.stringify(obj); // '{"name":"Kim","age":30,"active":true}'
const parsed = JSON.parse(json);  // { name: 'Kim', age: 30, active: true }

Map์€ JSON ์ง๋ ฌํ™”๋ฅผ ๋„ค์ดํ‹ฐ๋ธŒ๋กœ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

const map = new Map([['name', 'Kim'], ['age', 30]]);

JSON.stringify(map); // '{}'  โ† ๋นˆ ๊ฐ์ฒด๊ฐ€ ๋ฉ๋‹ˆ๋‹ค

// ๋ณ€ํ™˜์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค
JSON.stringify(Object.fromEntries(map)); // '{"name":"Kim","age":30}'

// ๋ณต์›
new Map(Object.entries(JSON.parse(json)));

API ์‘๋‹ต, ์„ค์ • ํŒŒ์ผ, ๋ฐ์ดํ„ฐ ๊ตํ™˜ ๋“ฑ JSON์ด ํ•„์š”ํ•œ ๊ณณ์—์„œ๋Š” Object๊ฐ€ ์ž์—ฐ์Šค๋Ÿฝ์Šต๋‹ˆ๋‹ค.

WeakMap: ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋ฐฉ์ง€

Map์˜ ํŠน์ˆ˜ํ•œ ๋ณ€ํ˜•์ธ WeakMap์€ ํ‚ค์— ๋Œ€ํ•œ ์•ฝํ•œ ์ฐธ์กฐ๋ฅผ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค. ํ‚ค๋กœ ์‚ฌ์šฉ๋œ ๊ฐ์ฒด๊ฐ€ ๋‹ค๋ฅธ ๊ณณ์—์„œ ์ฐธ์กฐ๋˜์ง€ ์•Š์œผ๋ฉด ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜ ๋Œ€์ƒ์ด ๋ฉ๋‹ˆ๋‹ค.

const metadata = new WeakMap();

function processElement(element) {
  // DOM ์š”์†Œ์— ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ์—ฐ๊ฒฐ
  metadata.set(element, {
    clickCount: 0,
    lastAccessed: Date.now(),
  });
}

// element๊ฐ€ DOM์—์„œ ์ œ๊ฑฐ๋˜๊ณ  ๋‹ค๋ฅธ ์ฐธ์กฐ๋„ ์—†์œผ๋ฉด,
// WeakMap์˜ ์—”ํŠธ๋ฆฌ๋„ ์ž๋™์œผ๋กœ ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜๋ฉ๋‹ˆ๋‹ค.
// Map์ด์—ˆ๋‹ค๋ฉด ๋ช…์‹œ์ ์œผ๋กœ deleteํ•˜์ง€ ์•Š๋Š” ํ•œ ๋ฉ”๋ชจ๋ฆฌ์— ๋‚จ์Šต๋‹ˆ๋‹ค.

WeakMap์˜ ์ œ์•ฝ์‚ฌํ•ญ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ํ‚ค๋Š” ๊ฐ์ฒด ๋˜๋Š” ๋“ฑ๋ก๋˜์ง€ ์•Š์€ Symbol๋งŒ ๊ฐ€๋Šฅ (์›์‹œ๊ฐ’ ๋ถˆ๊ฐ€)
  • iterable์ด ์•„๋‹˜ โ€” keys(), values(), entries(), forEach, size ์—†์Œ
  • ์ˆœํšŒํ•  ์ˆ˜ ์—†๋Š” ์ด์œ ๋Š” ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜ ํƒ€์ด๋ฐ์ด ๋น„๊ฒฐ์ •์ ์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค

๋Œ€ํ‘œ์ ์ธ ํ™œ์šฉ ์‚ฌ๋ก€๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

// 1. ํ”„๋ผ์ด๋น— ๋ฐ์ดํ„ฐ
const privates = new WeakMap();

class Counter {
  constructor() {
    privates.set(this, { count: 0 });
  }
  increment() {
    const data = privates.get(this);
    data.count++;
  }
  getCount() {
    return privates.get(this).count;
  }
}
// Counter ์ธ์Šคํ„ด์Šค๊ฐ€ GC๋˜๋ฉด private ๋ฐ์ดํ„ฐ๋„ ํ•จ๊ป˜ ์‚ฌ๋ผ์ง‘๋‹ˆ๋‹ค.

// 2. ์บ์‹œ
const cache = new WeakMap();

function expensiveComputation(obj) {
  if (cache.has(obj)) return cache.get(obj);
  const result = /* ๋น„์šฉ์ด ํฐ ๊ณ„์‚ฐ */ obj;
  cache.set(obj, result);
  return result;
}
// obj๊ฐ€ ๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š์œผ๋ฉด ์บ์‹œ๋„ ์ž๋™ ์ •๋ฆฌ๋ฉ๋‹ˆ๋‹ค.

์–ธ์ œ ๋ญ˜ ์จ์•ผ ํ•˜๋‚˜

Object๋ฅผ ์“ฐ๋Š” ๊ฒฝ์šฐ:

  • ๊ตฌ์กฐ๊ฐ€ ๊ณ ์ •๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ํ‘œํ˜„ํ•  ๋•Œ ({ name, age, email })
  • JSON๊ณผ ์ง์ ‘ ๋ณ€ํ™˜์ด ํ•„์š”ํ•  ๋•Œ
  • ๊ตฌ์กฐ ๋ถ„ํ•ด ํ• ๋‹น, ์Šคํ”„๋ ˆ๋“œ ๋ฌธ๋ฒ•์„ ํ™œ์šฉํ•  ๋•Œ
  • ๋ฉ”์„œ๋“œ๋ฅผ ํฌํ•จํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค ๋•Œ
// โœ… Object๊ฐ€ ์ ํ•ฉํ•œ ๊ฒฝ์šฐ
const config = {
  host: 'localhost',
  port: 3000,
  debug: true,
};

const { host, port } = config; // ๊ตฌ์กฐ ๋ถ„ํ•ด
const extended = { ...config, port: 8080 }; // ์Šคํ”„๋ ˆ๋“œ

Map์„ ์“ฐ๋Š” ๊ฒฝ์šฐ:

  • ํ‚ค๊ฐ€ ๋ฌธ์ž์—ด์ด ์•„๋‹Œ ๊ฒฝ์šฐ (DOM ์š”์†Œ, ๊ฐ์ฒด ๋“ฑ)
  • ํ‚ค-๊ฐ’ ์Œ์ด ๋™์ ์œผ๋กœ ์ž์ฃผ ์ถ”๊ฐ€/์‚ญ์ œ๋˜๋Š” ๊ฒฝ์šฐ
  • ์‚ฝ์ž… ์ˆœ์„œ๊ฐ€ ์ค‘์š”ํ•œ ๊ฒฝ์šฐ
  • ์—”ํŠธ๋ฆฌ ๊ฐœ์ˆ˜๋ฅผ ์ž์ฃผ ํ™•์ธํ•˜๋Š” ๊ฒฝ์šฐ
  • ํ‚ค ์ด๋ฆ„์ด ์˜ˆ์ธกํ•  ์ˆ˜ ์—†๋Š” ์‚ฌ์šฉ์ž ์ž…๋ ฅ์ธ ๊ฒฝ์šฐ
// โœ… Map์ด ์ ํ•ฉํ•œ ๊ฒฝ์šฐ
const clickCounts = new Map();

document.querySelectorAll('button').forEach((btn) => {
  btn.addEventListener('click', () => {
    // DOM ์š”์†Œ๋ฅผ ํ‚ค๋กœ ์‚ฌ์šฉ
    const count = clickCounts.get(btn) || 0;
    clickCounts.set(btn, count + 1);
  });
});

// ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ
const handlers = new Map();
handlers.set(fetchUser, { retries: 3, timeout: 5000 });
handlers.set(fetchPosts, { retries: 1, timeout: 10000 });

WeakMap์„ ์“ฐ๋Š” ๊ฒฝ์šฐ:

  • ๊ฐ์ฒด์— ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ์—ฐ๊ฒฐํ•˜๋˜ ์ˆ˜๋ช…์„ ๊ฐ์ฒด์— ๋งž์ถ”๊ณ  ์‹ถ์„ ๋•Œ
  • ์บ์‹œ๋ฅผ ๊ตฌํ˜„ํ•˜๋˜ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๋ฅผ ๋ฐฉ์ง€ํ•˜๊ณ  ์‹ถ์„ ๋•Œ
  • ํ”„๋ผ์ด๋น— ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•  ๋•Œ

์ •๋ฆฌ

Object์™€ Map์€ ๊ฒ‰๋ณด๊ธฐ์— ๋น„์Šทํ•˜์ง€๋งŒ ์„ค๊ณ„ ๋ชฉ์ ์ด ๋‹ค๋ฆ…๋‹ˆ๋‹ค. Object๋Š” ํ”„๋กœํผํ‹ฐ์™€ ํ–‰์œ„๋ฅผ ๊ฐ€์ง„ ์—”ํ‹ฐํ‹ฐ๋ฅผ ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ด๊ณ , Map์€ ํ‚ค-๊ฐ’ ์Œ์˜ ์ปฌ๋ ‰์…˜์„ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ฝ”๋“œ์—์„œ {} ๋ฅผ ์Šต๊ด€์ ์œผ๋กœ ์“ฐ๊ณ  ์žˆ๋‹ค๋ฉด ํ•œ ๋ฒˆ ์ƒ๊ฐํ•ด ๋ณผ ๊ฐ€์น˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. "์ด๊ฑด ์—”ํ‹ฐํ‹ฐ์ธ๊ฐ€, ์ปฌ๋ ‰์…˜์ธ๊ฐ€?" ์—”ํ‹ฐํ‹ฐ๋ผ๋ฉด Object, ์ปฌ๋ ‰์…˜์ด๋ผ๋ฉด Map์ด ๋งž๋Š” ๋„๊ตฌ์ž…๋‹ˆ๋‹ค.

์ฐธ๊ณ