=> 결론적으로 데이터를 좀 더 유연하게 컨트롤할 수 있고, 내장함수를 통해 명확한 프로그래밍 구현이 가능하다.
또한 key, value를 추가하거나 제거할 때 Object에 비해 성능적으로 최적화 되어 있음
실제 MDN 문서에서도 Map vs Object 비교해놓게 있는데 Map 사용을 사용하는 걸 더 권장하는 걸 볼 수 있음
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Map
Iterator
- JavaScript에서 iterator는 데이터 집합(collection)을 반복(iterate)할 수 있는 객체(object)입니다.
- next(): iterator에서 다음 요소에 대한 정보를 반환합니다. 반환값은 {value: 값, done: boolean} 형태의 객체입니다.
- value 프로퍼티에는 다음 요소의 값이 들어 있고, done 프로퍼티에는 iterator에서 더 이상 요소가 없는지 여부가 들어 있습니다.
- iterator 객체는 Symbol.iterator 메서드를 가지고 있습니다. 이 메서드는 iterator 객체 자신을 반환하므로, for..of 루프 등에서 iterator 객체를 사용할 수 있습니다.
- 예를 들어, 다음과 같이 배열(array)을 iterator로 변환하고, for..of 루프를 사용하여 각 요소를 출력할 수 있습니다:
- Iterator는 ES6(ES2015)부터 도입된 개념으로, Map, Set, Array 등의 내장 객체에서 사용할 수 있습니다. 또한, 직접 Iterator 객체를 구현하여 사용할 수도 있습니다.
const arr = [1, 2, 3]; const iterator = arr[Symbol.iterator](); for (const value of iterator) { console.log(value); } // 출력: // 1 // 2 // 3
ex)
const nm = new Map();
nm.set('a', 0);
nm.set('b', 1);
nm.set('c', 2);
for (const [k, v] of nm) {
console.log(k, v)
// 'a', 0
// 'b', 1
// 'c', 2
}
nm.forEach((v: number, k: string) => {
console.log(k, v);
// 'a', 0
// 'b', 1
// 'c', 2
})
// 키 값 존재 여부
console.log(nm.has('a')) // true
console.log(nm.has('z')) // false
const obj = { a: 'b' };
nm.set(obj, 123);
console.log(nm.get(obj)) // 123;
// delete
nm.delete(obj)
console.log(nm.has(obj)) // false;
// 모든 Key, Value 삭제
nm.clear();
console.log(nm.size) // 0
console.log(nm); // {}
예를들어 어떤 가게에서 손님 이름과 지역을 저장하는 배열이 있다고 가정
let guestArr = [
{ name: 'a', city: 'seoul' },
{ name: 'b', city: 'seoul' },
{ name: 'c', city: 'busan' },
{ name: 'd', city: 'busan' },
{ name: 'e', city: 'busan' },
{ name: 'f', city: 'incheon' },
{ name: 'g', city: 'hwaseong' },
{ name: 'h', city: 'jeju' },
]
해당 값에서 도시별로 누가 왔는지 알고 싶어서 아래와 같은 객체를 얻고 싶다면?
{
seoul: [ { name: 'a', city: 'seoul' }, { name: 'b', city: 'seoul' } ],
busan: [
{ name: 'c', city: 'busan' },
{ name: 'd', city: 'busan' },
{ name: 'e', city: 'busan' }
],
incheon: [ { name: 'f', city: 'incheon' } ],
hwaseong: [ { name: 'g', city: 'hwaseong' } ],
jeju: [ { name: 'h', city: 'jeju' } ]
}
let oGuest = {};
guestArr.forEach(item => {
if (!oGuest[item.city]) {
oGuest[item.city] = [];
}
oGuest[item.city].push(item);
})
console.log(oGuest)
위 예시에서 if 문안에 들어가 있는 값은 boolean(true, false) 값이 아님.
javascript에서는 if 문 안에 0, undefined인 경우도 false로 인식하기 때문에 위 if문에서 !oGuest[item.city] 는 !undefined => true로 인식하게 되어 있음
이를 통해 key로 지역, value로 빈 배열을 생성하고 해당 name, city를 추가하는 구조
=> 즉, 명확한 true, false 의도로 프로그래밍 할 수 없는 예외상황 발생할 수 있음
let mapGuest = new Map();
guestArr.forEach(item => {
if (!mapGuest.has(item.city)) {
mapGuest.set(item.city, []);
mapGuest.get(item.city).push(item);
}
})
console.log(mapGuest)
has(key) 메서드는 boolean(true, false)를 반환하기 떄문에 명확한 프로그래밍 구현 가능
기존 객체 반복문의 경우 for...in을 쓸때 프로토타입 속성까지 다 복사해버리기 떄문에
명확하게 원본 값만 반복하기 위해 hasOwnProperty() 와 같은 처리를 해줘야함
const obj = { ... };
'
for (let i in obj2) {
if (obj.hasOwnProperty(i)) {
obj[i];
}
}
(만약 Typscript에서 쓴다면 정적인 타입을 지정해줘야 하기 떄문에 객체에 Record<string, unknown>와 같은 추가적인 처리를 더 해줘야 한다... )
하지만 new Map()의 경우 반복문, foreach를 사용할 수 있기 때문에
const nm = new Map();
nm.set('a', 0);
nm.set('b', 1);
nm.set('c', 2);
for (const [k, v] of nm) {
console.log(k, v)
// 'a', 0
// 'b', 1
// 'c', 1
}
nm.forEach((v: number, k: string) => {
console.log(k, v);
// 'a', 0
// 'b', 1
// 'c', 1
})
이런식으로 처리가 가능하다
const s = new Set();
s.add(1);
s.add(2);
s.add(3);
console.log(s); // { 1, 2, 3 }
console.log(s.size); // 3
// 반복, foreach 사용 가능
for (const a of s) {
console.log(a); // 1, 2, 3
}
s.forEach(a => {
console.log(a); // 1, 2, 3
})
s.delete(2);
console.log(s); // { 1, 3 }
s.clear();
console.log(s); // {}
기존 배열의 중복을 제거하고 싶을 때?
(알고리즘 써도 간단하게 되긴 하지만...)
const arr = [1, 3, 2, 7, 2, 6, 3, 5];
const ns = new Set(arr);
const result = Array.from(ns);
console.log(result); // [1, 3, 2, 7, 6, 5]
ex)
const obj = {};
const user = { id: 1, name: 'hong' }';
const wm = new WeakMap();
wm.set(obj, user)
...
...
user = null;