Language/JavaScript

[JS] πŸ“š μžλ°”μŠ€ν¬λ¦½νŠΈ μžλ£Œν˜• Map 🚩 정리

인파_ 2021. 10. 5. 15:05

Map

 

μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” 객체와 λ°°μ—΄μ΄λΌλŠ” κ°•λ ₯ν•œ 자료ꡬ쑰λ₯Ό μ œκ³΅ν•©λ‹ˆλ‹€.

  • ​객체 – ν‚€κ°€ μžˆλŠ” μ»¬λ ‰μ…˜μ„ μ €μž₯함
  • λ°°μ—΄ – μˆœμ„œκ°€ μžˆλŠ” μ»¬λ ‰μ…˜μ„ μ €μž₯함

β€‹ν•˜μ§€λ§Œ ν˜„μ‹€ 세계λ₯Ό λ°˜μ˜ν•˜κΈ°μ—” 이 두 자료ꡬ쑰 만으둠 λΆ€μ‘±ν•΄μ„œ 맡(Map)κ³Ό μ…‹(Set)이 λ“±μž₯ν•˜κ²Œ λ˜μ—ˆμŠ΅λ‹ˆλ‹€.


Map μžλ£Œν˜•

​킀가 μžˆλŠ” 데이터λ₯Ό μ €μž₯ν•œλ‹€λŠ” μ μ—μ„œ 객체와 μœ μ‚¬ν•©λ‹ˆλ‹€.

λ‹€λ§Œ, 맡은 킀에 λ‹€μ–‘ν•œ μžλ£Œν˜•μ„ ν—ˆμš©ν•œλ‹€λŠ” μ μ—μ„œ 차이가 μžˆμŠ΅λ‹ˆλ‹€.

(객체의 keyλŠ” 항상 μŠ€νŠΈλ§ν˜•νƒœλ‘œ μ €μž₯λ©λ‹ˆλ‹€.)

let map1 = new Map([ // 2차원 key, value ν˜•νƒœμ˜ λ°°μ—΄
    ['a',1],
    ['a1',2],
    ['b',3]
])
// map μžλ£Œν˜• : {"a" => 1, "a1" => 2, "b" => 3}

new Map() – 맡을 λ§Œλ“­λ‹ˆλ‹€.

map.set(key, value) – keyλ₯Ό μ΄μš©ν•΄ valueλ₯Ό μ €μž₯ν•©λ‹ˆλ‹€.

map.get(key) – key에 ν•΄λ‹Ήν•˜λŠ” 값을 λ°˜ν™˜ν•©λ‹ˆλ‹€. keyκ°€ μ‘΄μž¬ν•˜μ§€ μ•ŠμœΌλ©΄ undefinedλ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.

map.has(key) – keyκ°€ μ‘΄μž¬ν•˜λ©΄ true, μ‘΄μž¬ν•˜μ§€ μ•ŠμœΌλ©΄ falseλ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.

map.delete(key) – key에 ν•΄λ‹Ήν•˜λŠ” 값을 μ‚­μ œν•©λ‹ˆλ‹€.

map.clear() – 맡 μ•ˆμ˜ λͺ¨λ“  μš”μ†Œλ₯Ό μ œκ±°ν•©λ‹ˆλ‹€.

map.size – μš”μ†Œμ˜ 개수λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.

 

let map = new Map();

map.set('1', 'str1');   // λ¬Έμžν˜• ν‚€
map.set(1, 'num1');     // μˆ«μžν˜• ν‚€
map.set(true, 'bool1'); // λΆˆλ¦°ν˜• ν‚€

/* 2차원 λ°°μ—΄ ν˜•νƒœλ‘œ ν•œλ°©μ— μ„ μ–Έ ν•  수 μžˆμ–΄μš”
let map = new Map([
   ['1', 'str1'],
   [1, 'num1'],
   [true, 'bool1']
])*/

// κ°μ²΄λŠ” ν‚€λ₯Ό λ¬Έμžν˜•μœΌλ‘œ λ³€ν™˜ν•œλ‹€λŠ” κ±Έ κΈ°μ–΅ν•˜κ³  κ³„μ‹ κ°€μš”?
// 맡은 ν‚€μ˜ νƒ€μž…μ„ λ³€ν™˜μ‹œν‚€μ§€ μ•Šκ³  κ·ΈλŒ€λ‘œ μœ μ§€ν•©λ‹ˆλ‹€. λ”°λΌμ„œ μ•„λž˜μ˜ μ½”λ“œλŠ” 좜λ ₯λ˜λŠ” 값이 λ‹€λ¦…λ‹ˆλ‹€.
alert( map.get(1)   ); // 'num1'
alert( map.get('1') ); // 'str1'

alert( map.size ); // 3

Map

맡의 key에 쀑볡값이 있으면 λ‚˜μ€‘κ°’μœΌλ‘œ μ μš©λ©λ‹ˆλ‹€. (μ΄λŠ” 객체도 λ§ˆμ°¬κ°€μ§€)

let map1 = new Map([
    ['a',1],
    ['a',2],
    ['b',3]
]) // {"a" => 2, "b" => 3}

let object1 = {
    a:1,
    a:2,
    b:3
} // {a: 2, b: 3}
const errorMessageObj = {
    404 : "νŽ˜μ΄μ§€κ°€ μ—†μŠ΅λ‹ˆλ‹€",
    500 : "μ„œλ²„ 였λ₯˜μž…λ‹ˆλ‹€",
    401 : "κΆŒν•œμ΄ μ—†μŠ΅λ‹ˆλ‹€"
}

errorMessageObj.404         // unexpected number μ—λŸ¬. key값은 λ¬Έμžμ—΄ μ²˜λ¦¬κ°€ λ˜μ–΄μ„œ λ¬Έμžμ—΄λ‘œ 접근해야함
errorMessageObj["404"]      // 'νŽ˜μ΄μ§€κ°€ μ—†μŠ΅λ‹ˆλ‹€' 정상접근


const errorMessageMap = new Map([
    [404, "νŽ˜μ΄μ§€κ°€ μ—†μŠ΅λ‹ˆλ‹€"],
    [500, "μ„œλ²„ 였λ₯˜μž…λ‹ˆλ‹€"],
    [401, "κΆŒν•œμ΄ μ—†μŠ΅λ‹ˆλ‹€"],
])

errorMessageMap.get(404)    // 'νŽ˜μ΄μ§€κ°€ μ—†μŠ΅λ‹ˆλ‹€' λ”°λ‘œ λ¬Έμžμ—΄ μ²˜λ¦¬μ—†μ΄, 정상접근

맡은 객체와 달리 ν‚€λ₯Ό λ¬Έμžν˜•μœΌλ‘œ λ³€ν™˜ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. ν‚€μ—” μžλ£Œν˜• μ œμ•½μ΄ μ—†μŠ΅λ‹ˆλ‹€.

​map[key]λŠ” Map을 μ“°λŠ” λ°”λ₯Έ 방법이 μ•„λ‹™λ‹ˆλ‹€.
map[key] = 2둜 값을 μ„€μ •ν•˜λŠ” 것 같이 map[key]λ₯Ό μ‚¬μš©ν•  수 있긴 ν•©λ‹ˆλ‹€. ν•˜μ§€λ§Œ 이 방법은 map을 일반 객체처럼 μ·¨κΈ‰ν•˜κ²Œ λ©λ‹ˆλ‹€. λ”°λΌμ„œ μ—¬λŸ¬ μ œμ•½μ΄ μƒκΈ°κ²Œ 되죠.
map을 μ‚¬μš©ν•  땐 mapμ „μš© λ©”μ„œλ“œ set, get 등을 μ‚¬μš©ν•΄μ•Όλ§Œ ν•©λ‹ˆλ‹€.

 

맡은 ν‚€λ‘œ 객체도 ν—ˆμš©ν•©λ‹ˆλ‹€.

let john = { name: "John" };

// 고객의 κ°€κ²Œ λ°©λ¬Έ 횟수λ₯Ό μ„Έλ³Έλ‹€κ³  κ°€μ •ν•΄ λ΄…μ‹œλ‹€.
let visitsCountMap = new Map();

// john을 맡의 ν‚€λ‘œ μ‚¬μš©ν•˜κ² μŠ΅λ‹ˆλ‹€.
visitsCountMap.set(john, 123);

alert( visitsCountMap.get(john) ); // 123

​

λ‹€μŒμ€ guestArr 배열에 이름과 μ‚΄κ³ μžˆλŠ” λ„μ‹œκ°€ μ €μž₯λ˜μ–΄ μžˆλŠ” μžλ£Œλ“€μ΄ μ €μž₯λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

이λ₯Ό λ„μ‹œλ³„λ‘œ λ¬Άμ–΄ μƒˆλ‘œ 자료λ₯Ό μ €μž₯ν•˜λ €κ³  ν•©λ‹ˆλ‹€.

let guestArr = [
    {name:"A", city:"Seoul"},
    {name:"B", city:"Busan"},
    {name:"C", city:"Seoul"},
    {name:"D", city:"Sejong"},
    {name:"E", city:"Busan"},
    {name:"F", city:"Sejong"},
    {name:"G", city:"Dawgeon"},
    {name:"H", city:"Sejong"},
    {name:"I", city:"Dawgeon"},
    {name:"J", city:"Busan"},
    {name:"K", city:"Seoul"},
]
let Oguest = {};
guestArr.forEach(item => {
    if (!Oguest[item.city])   Oguest[item.city] = [];
    Oguest[item.city].push(item);
});

console.log("[Object] : ", Oguest);

 

forEach()λ₯Ό μ‚¬μš©ν•΄μ„œ κΈ°μ‘΄ 객체 μ €μž₯법을 μ‚¬μš©ν•˜λ©΄ μ΄λ ‡κ²Œ λ©λ‹ˆλ‹€.

λ¨Όμ € μƒˆλ‘œμš΄ 객체 Oguest에 ν•΄λ‹Ή λ„μ‹œλͺ… item.cityκ°€ μ—†μœΌλ©΄ = [] 배열을 μƒˆλ‘œ λ„£μ–΄μ€λ‹ˆλ‹€.

그리고 push()λ₯Ό 톡해 객체λ₯Ό λ„£μ–΄μ€λ‹ˆλ‹€.

​

μ—¬κΈ°μ„œ key값이 될 item.cityλŠ” 슀트링이 μ €μž₯된 λ³€μˆ˜ν˜•νƒœ 인데,

이λ₯Ό 객체에 λ°›μ•„μ˜€κΈ° μœ„ν•΄μ„ , Oguest.item.city = [] ν˜•νƒœλ‘œ ν• μˆ˜λŠ” μ—†μŠ΅λ‹ˆλ‹€. μ™œλƒν•˜λ©΄ 객체 keyμ—λŠ” λ³€μˆ˜κ°€ 올수 μ—†κ³  무쑰건 슀트링만 였기 λ•Œλ¬Έμ΄μ£ .

κ·Έλž˜μ„œ λ°°μ—΄ν˜•νƒœλ‘œ μ ‘κ·Όν•΄μ„œ μΈλ±μŠ€μ— λ„£λŠ” μ‹μœΌλ‘œ ν•΄μ•Ό ν•©λ‹ˆλ‹€. Oguest[item.city] = []


ν•˜μ§€λ§Œ Map을 μ“°λ©΄ 쒀더 μ§κ΄€μ μœΌλ‘œ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

map.has()둜 킀값을 κ²€μ‚¬ν•˜κ³ , μ—†μœΌλ©΄ map.set()을 톡해 key와 valueλ₯Ό λ„£μ–΄μ€λ‹ˆλ‹€.

그리고 map.get으둜 keyλ₯Ό 가져와 value에 μžˆλŠ” 배열에 push() ν•΄μ€λ‹ˆλ‹€.

let Mguest = new Map();
guestArr.forEach(item => {
    if (!Mguest.has(item.city))   Mguest.set(item.city, []);
    Mguest.get(item.city).push(item);
});

console.log("[Map] : ", Mguest);

Map

 

체이닝

map.set을 ν˜ΈμΆœν•  λ•Œλ§ˆλ‹€ 맡 μžμ‹ μ΄ λ°˜ν™˜λ©λ‹ˆλ‹€.
이λ₯Ό μ΄μš©ν•˜λ©΄ map.set을 '체이닝(chaining)'ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

map.set('1', 'str1') .set(1, 'num1') .set(true, 'bool1');

Map


맡의 μš”μ†Œμ— 반볡 μž‘μ—…ν•˜κΈ°

​

λ‹€μŒ μ„Έ 가지 λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•΄ 맡의 각 μš”μ†Œμ— 반볡 μž‘μ—…μ„ ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

map.keys() – 각 μš”μ†Œμ˜ ν‚€λ₯Ό λͺ¨μ€ 반볡 κ°€λŠ₯ν•œ(iterable, μ΄ν„°λŸ¬λΈ”) 객체λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.

map.values() – 각 μš”μ†Œμ˜ 값을 λͺ¨μ€ μ΄ν„°λŸ¬λΈ” 객체λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.

map.entries() – μš”μ†Œμ˜ [ν‚€, κ°’]을 ν•œ 쌍으둜 ν•˜λŠ” μ΄ν„°λŸ¬λΈ” 객체λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€. 이 μ΄ν„°λŸ¬λΈ” κ°μ²΄λŠ” for..of반볡문의 기초둜 μ“°μž…λ‹ˆλ‹€.

let recipeMap = new Map([
  ['cucumber', 500],
  ['tomatoes', 350],
  ['onion',    50]
]);

// ν‚€(vegetable)λ₯Ό λŒ€μƒμœΌλ‘œ μˆœνšŒν•©λ‹ˆλ‹€.
for (let vegetable of recipeMap.keys()) {
  alert(vegetable); // cucumber, tomatoes, onion
}

// κ°’(amount)을 λŒ€μƒμœΌλ‘œ μˆœνšŒν•©λ‹ˆλ‹€.
for (let amount of recipeMap.values()) {
  alert(amount); // 500, 350, 50
}

// [ν‚€, κ°’] μŒμ„ λŒ€μƒμœΌλ‘œ μˆœνšŒν•©λ‹ˆλ‹€.
for (let entry of recipeMap) { // recipeMap.entries()와 λ™μΌν•©λ‹ˆλ‹€.
  alert(entry); // cucumber,500 ...
}

Map

 

맡은 μ‚½μž… μˆœμ„œλ₯Ό κΈ°μ–΅ν•©λ‹ˆλ‹€. (μ΄ν„°λŸ¬λΈ” 객체)
맡은 값이 μ‚½μž…λœ μˆœμ„œλŒ€λ‘œ 순회λ₯Ό μ‹€μ‹œν•©λ‹ˆλ‹€.
객체가 ν”„λ‘œνΌν‹° μˆœμ„œλ₯Ό κΈ°μ–΅ν•˜μ§€ λͺ»ν•˜λŠ” κ²ƒκ³ΌλŠ” λ‹€λ¦…λ‹ˆλ‹€.

 

여기에 λ”ν•˜μ—¬ 맡은 λ°°μ—΄κ³Ό μœ μ‚¬ν•˜κ²Œ λ‚΄μž₯ λ©”μ„œλ“œ forEach도 μ§€μ›ν•©λ‹ˆλ‹€.

// 각 (ν‚€, κ°’) μŒμ„ λŒ€μƒμœΌλ‘œ ν•¨μˆ˜λ₯Ό μ‹€ν–‰
recipeMap.forEach( (value, key, map) => {
  alert(`${key}: ${value}`); // cucumber: 500 ...
});

객체 -> 맡 으둜 λ°”κΎΈκΈ°

ν‰λ²”ν•œ 객체λ₯Ό 가지고 맡을 λ§Œλ“€κ³  μ‹Άλ‹€λ©΄ λ‚΄μž₯ λ©”μ„œλ“œ Object.entries(obj)λ₯Ό ν™œμš©ν•΄μ•Ό ν•©λ‹ˆλ‹€.

이 λ©”μ„œλ“œλŠ” 객체의 ν‚€-κ°’ μŒμ„ μš”μ†Œ([key, value])둜 κ°€μ§€λŠ” 배열을 λ°˜ν™˜ν•©λ‹ˆλ‹€.

// κ·Έλƒ₯ 맡 λ§Œλ“€κΈ° (각 μš”μ†Œκ°€ [ν‚€, κ°’] 쌍인 λ°°μ—΄)
let map = new Map([
  ['1',  'str1'],
  [1,    'num1'],
  [true, 'bool1']
]);


// 객체둜 맡 λ§Œλ“€κΈ°
let obj = {
  name: "John",
  age: 30
};

let map2 = new Map(Object.entries(obj)); // 객체λ₯Ό 2μ°¨μ›μ˜ ν‚€:λ°Έλ₯˜ ν˜•νƒœλ‘œ λ§Œλ“€κ³  맡으둜 λ³€ν™˜
                                         // [ ["name","John"], ["age", 30] ]
alert( map2.get('name') ); // John

Object.entriesλ₯Ό μ‚¬μš©ν•΄ 객체 objλ₯Ό λ°°μ—΄ [ ["name","John"], ["age", 30] ]둜 λ°”κΎΈκ³ , 이 배열을 μ΄μš©ν•΄ μƒˆλ‘œμš΄ 맡을 λ§Œλ“€μ–΄λ³΄μ•˜μŠ΅λ‹ˆλ‹€.

​

맡 -> 객체 둜 λ°”κΎΈκΈ°

이 λ°˜λŒ€μΈ 맡을 객체둜 λ°”κΎΈλŠ” 방법에 λŒ€ν•΄ μ•Œμ•„λ³΄κ² μŠ΅λ‹ˆλ‹€.

Object.fromEntriesλ₯Ό μ‚¬μš©ν•˜λ©΄ κ°€λŠ₯ν•©λ‹ˆλ‹€. 이 λ©”μ„œλ“œλŠ” 각 μš”μ†Œκ°€ [ν‚€, κ°’] 쌍인 배열을 객체둜 λ°”κΏ”μ€λ‹ˆλ‹€.

μžλ£Œκ°€ 맡에 μ €μž₯λ˜μ–΄μžˆλŠ”λ°, μ„œλ“œνŒŒν‹° μ½”λ“œμ—μ„œ 자료λ₯Ό κ°μ²΄ν˜•νƒœλ‘œ λ„˜κ²¨λ°›κΈΈ 원할 λ•Œ 이 방법을 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

let map = new Map();
map.set('banana', 1);
map.set('orange', 2);
map.set('meat', 4);

let obj = Object.fromEntries(map.entries()); // 맡을 일반 객체둜 λ³€ν™˜ (*)
// let obj = Object.fromEntries(map); // .entries()λ₯Ό μƒλž΅ν•  수 있음.
// 맡이 객체가 λ˜μ—ˆμŠ΅λ‹ˆλ‹€!
// obj = { banana: 1, orange: 2, meat: 4 }

alert(obj.orange); // 2

Reference

https://ko.javascript.info/map-set 

https://maxkim-j.github.io/posts/js-map