이전에 우리가 알고있는 자료구조는
객체 - 키가 있는 컬렉션을 저장함
배열 - 순서가 있는 렉션을 저장함
였지만 현실세계를 반영하기에는 이 두 자료구조 만으론 부족해서 Map Object가 만들어졌다.
맵 객체 메소드
맵 객체는 기존 객체와는 다르게 메소드만을 이용해 값을 넣고 뺀다.
기본적으로 추가, 조회, 삭제를 할 수 있는 메소드들은 아래와 같다
//변수명 자유롭게 설정 가능
let map = new Map();
// set으로 맵 객체에 추가
map.set("id", 0);
map.set("이름", "마이클");
map.set("전공", "영문학");
map.set("나이", 25);
// 이런식으로 정의할때부터 바로 넘겨줄 수 도 있음
let michael = new Map([
["id", 0],
["이름", "마이클"],
["전공", "영문학"],
["나이", 29]
])
// get으로 맵 객체 조회
map.get("이름"); // "마이클" // key가 존재하지 않으면 undefined 반환
// delete로 삭제
map.delete("나이"); // 삭제가 성공하면 true를 반환
// has
map.has("나이")); // true // key가 존재하면 true, 존재하지 않으면 false 반환
// clear로 맵 안의 프로퍼티 전부삭제
map.clear();
// 요소의 개수를 반환한다.
map.size
이외에도 다른 메소드를 쓸 수 있다.
객체의 메소드가 매우 제한적인것에 반해,
맵 객체는 풍부한 메소드를 제공하고 있다.
맵 객체의 장점
문자열 아닌 값도 키로 사용 가능
객체에서는 string or Symbol만 프로퍼티의 키로 사용할 수 있지만 맵 객체에서는 함수나 객체를 포함한 모든 자료형이 프로퍼티의 키로 쓰일 수 있다.
let map = new Map();
map.set('1', 'str1'); // 문자형 키
map.set(1, 'num1'); // 숫자형 키
map.set(true, 'bool1'); // 불린형 키
// 객체는 키를 문자형으로 변환한다는 걸 기억하고 계신가요?
// 맵은 키의 타입을 변환시키지 않고 그대로 유지합니다.
// 따라서 아래의 코드는 출력되는 값이 다릅니다.
alert( map.get(1) ); // 'num1'
alert( map.get('1') ); // 'str1'
alert( map.size ); // 3
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);
console.log( visitsCountMap.get(john) ); // 123
console.log(john.name) // John
//이런식으로 객체의 장점 맵의 장점 모두 이용
객체를 키로 사용할 수 있다는 점은 맵의 가장 중요한 기능 중 하나이다.
객체에는 문자열 키를 사용할 수 있다
하지만 객체 키는 사용할 수 없다.
객체형 키를 객체에 쓴다면
let john = { name: "John" };
let visitsCountObj = {}; // 객체를 하나 만듭니다.
visitsCountObj[john] = 123; // 객체(john)를 키로 해서 객체에 값(123)을 저장해봅시다.
// 원하는 값(123)을 얻으려면 아래와 같이 키가 들어갈 자리에 `object Object`를 써줘야합니다.
console.log( visitsCountObj["[object Object]"] ); // 123
맵이 키를 비교하는 방식
맵은 SameValueZero라 불리는 알고리즘을 사용해 값의 등가 여부를 확인합니다.
이 알고리즘은 일치 연산자 ===와 거의 유사하지만, NaN과 NaN을 같다고 취급하는 것에서 일치 연산자와 차이가 있습니다.
따라서 맵에선 NaN도 키로 쓸 수 있습니다.
이 알고리즘은 수정하거나 커스터마이징 하는 것이 불가능합니다
체이닝
map.set을 호출할 때마다 맵 자신이 반환됩니다. 이를 이용하면 map.set을 '체이닝(chaining)'할 수 있습니다
map.set('1', 'str1')
.set(1, 'num1')
.set(true, 'bool1');
가독성 향상
객체와 달리 맵 객체는 메소드의 이름들 (set, get, delete, clear)이 어떤 동작을 할 것인지를 잘 나타내주고 있어서 가독성이 더 좋다
let maxInfoObj = {
age:25,
major:"영문학",
}
const maxInfoMap = new Map([
["age", 25],
["major", "영문학"],
])
// 객체 : let으로 선언해 빈 객체 할당해서 빈 객체로 초기화
maxInfoObj = {}
// 맵 객체 : clear 메소드 사용해 빈 맵 객체로 초기화
maxInfoMap.clear()
깔끔한 순회
맵 객체는 그 자체로 for ... of 문을 통해 순회가 가능합니다. 이때 순회는 맵 이터레이터의 형태로 이루어진다
맵 이터레이터는 key-value을 쌍으로 묶은 배열이다.
entries 메소드로 맵 이터레이터를 확인할 수 있다.
const recipeMap = new Map([
['cucumber', 500],
['tomatoes', 350],
['onion', 50]
])
recipeMap.entries();
// [Map Entries] {[ 'cucumber', 500 ],[ 'tomatoes', 350 ],[ 'onion', 50 ]}
// [키, 값] 쌍을 대상으로 순회합니다.
for (let entry of recipeMap) {
console.log(entry); // {[ 'cucumber', 500 ],[ 'tomatoes', 350 ],[ 'onion', 50 ]}
// 객체와 배열안에 담겨서 나옴
// recipeMap.entries()와 비슷하다 이것은 결과값만 나온다
}
// 바로 결과 값만 받게도 할 수 있음
for (let [key, value] of recipeMap) {
console.log(key, value);
//cucumber 500
//tomatoes 350
//onion 50
}
// 키(vegetable)를 대상으로 순회합니다.
for (let vegetable of recipeMap.keys()) {
console.log(vegetable); //cucumber tomatoes onion
}
// 값(amount)을 대상으로 순회합니다.
for (let amount of recipeMap.values()) {
console.log(amount); // 500 350 50
}
가변성
객체를 맵으로 바꾸거나 맵을 객체로 바꿀 수도 있다.
Object.entries: 객체를 맵으로 바꾸기
배경지식으로 이것을 알면 좋다.
// 각 요소가 [키, 값] 쌍인 배열
let map = new Map([
['1', 'str1'],
[1, 'num1'],
[true, 'bool1']
]);
console.log( map.get('1') ); // str1
이렇게 set말고도 map에 key - value를 전달하는 방법을 알고서 아래를 보면 이해하기 쉽다
평범한 객체를 가지고 맵을 만들고 싶다면 내장 메서드 Object.entries(obj)을 사용해야 한다.
이 메서드는 객체의 키-값 쌍을 요소로 가지는 배열을 반환한다.
let obj = {
name: "John",
age: 30
};
console.log(Object.entries(obj)) // [ [ 'name', 'John' ], [ 'age', 30 ] ]
let map = new Map(Object.entries(obj));
console.log( map.get('name') ); // John
Object.fromEntries : 맵을 객체로 바꾸기
Object.fromEntries를 사용하면 가능하다.
이 메서드는 각 요소가 [키, 값] 쌍인 배열을 객체로 바꿔줍니다.
let prices = Object.fromEntries([
['banana', 1],
['orange', 2],
['meat', 4]
]);
// now prices = { banana: 1, orange: 2, meat: 4 }
console.log(prices.orange); // 2
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); 이렇게 해도 똑같이 동작함
// 맵이 객체가 되었습니다!
// obj = { banana: 1, orange: 2, meat: 4 }
console.log(obj.orange); // 2
'Javascript > 개념' 카테고리의 다른 글
[JS - 개념] delete (0) | 2022.07.03 |
---|---|
[JS - 개념] Filter() (0) | 2022.06.30 |
[JS - 개념] reduce() <feat.. Array.prototype.concat()> (0) | 2022.06.27 |
[JS - 개념 ] 자바스크립트에 점점점(...)의 기능 (0) | 2022.06.17 |
[JS - 개념] 정규표현식 (0) | 2022.06.11 |