최근에 면접을 보면서 Set과 Map에 대해 질문을 받았는데 그동안 코딩을 해오면서 중복된 요소를 제거하기 위해 사용한적 이외에는 사용해본적이 없어 적절한 답변을 하지 못해 이번에 Set과 Map에 대해 좀더 자세히 알아보려고 한다.
const set = new Set();
const obj1 = {sameObj: 1};
const obj2 = {sameObj: 1};
set.add(obj1);
set.add(obj2);
set.add(5);
set.add("5");
getLog(set);
// Set(4) { { sameObj: 1 }, { sameObj: 1 }, 5, '5' }
Set에서 value 비교는 자바스크립트의 ===와 동일
하기 때문에 obj1와 obj2는 다르다고 인식한다.
만약 obj2가 obj1와 동일한 주소를 참조한다면
const obj1 = {sameObj: 1}; const obj2 = obj1; // 생략 getLog(set); // Set(4) { { sameObj: 1 }, 5, '5' }
let set = new Set();
set.add(5);
set.add("5");
set.add(5); // 중복 시도
getLog(set.size); // 2
동일한 value를 사용했을 때 중복을 허용하지 않기때문
에 이후의 value를 사용하여 호출했을 때 무시된다는 특징이 있다.
Set은 순회할수 있는 객체이다.
따라서 for ...of문을 사용하여 순회할수도 있고 spread 연산자를 사용할수있다.
function intersection(setA, setB){
const set = new Set();
for (let value of setB) {
if(setA.has(value)) set.add(value);
}
return set;
}
function union(setA, setB){
const set = new Set([...setA, ...setB]);
return set;
}
Javascript 에서 객체가 iterable 하기 위해서는, object 에는 [@@iterator] 메소드가 구현되어 있어야 한다.
일반 객체와 가장 큰 차이점은 key로 어떠한 타입이어도 상관없다.
const person = new Map();
person.set('name', 'jiseong');
person.set('birthday', '0221');
person.set(1, '숫자형 key');
getLog(person); // Map(3) { 'name' => 'jiseong', 'birthday' => '0221', 1 => '숫자형 key' }
getLog(person.get('name')) // jiseong
getLog(person.has('name')); // true
getLog(person.size) // 3
객체의 프로퍼티는 항상 문자열로 강제 변환한다.
let map = Object.create(null); map[5] = "foo"; console.log(map["5"]); // "foo"
ES6에서 새로 추가된 컬렉션은 사용자의 데이터와 빌트인(built-in) 메서드의 이름이 충돌되지 않기 위해 설계되어 있어 직접적으로
obj.[key] obj.key
를 이용해 접근이 불가능하다고 한다.따라서 위의 코드로 예시를 들면
person['name']
으로 접근이 불가능하다.
Key의 중복은 허용되지 않아 동일한 Key값을 가진 값은 맨 마지막으로 호출한 value 값을 가지게 된다.
const map = new Map([['a', 1], ['a', 2]]);
getLog(map); // Map(1) { 'a' => 2 }
const person1 = {name: 'kim'};
const person2 = {name: 'lee'};
const map1 = new Map([[person1, '1999'], [person2, '2000']]);
for (const entry of map1) {
console.log(entry); // [ { name: 'kim' }, '1999' ] [ { name: 'lee' }, '2000' ]
}
Map과 Set 컬렉션의 등장으로 내가 생각하는 이점은 이들을 사용하면 key값으로 문자열 또는 Symbol만을 사용할 수 있었던 문제와 중복되는 key값 문제를 해결할 수 있다는 점이다. 뿐만 아니라 Iterable하기 때문에 일반 객체에 비해 유용한 문법들을 활용할 수 있다는 점이다.
최근 검색어기능에서 동일한 검색어를 입력했을때 filter를 사용하여 제거하는 방식을 사용했는데 Set을 사용하면 좀더 간결하게 작성할수있다.
export const customSearchHistory = (newItem: string, list: string[]) => {
// const newList = [newItem, ...list.filter((item) => item !== newItem)];
const newList = [...new Set([newItem, ...list])];
return newList.slice(0, 5);
};
Map과 Set이 참조하는 객체들은 강하게 연결되어 있어 GC이 메모리 수거하는데 어려움을 겪어 이를 해결하기 위해 나왔다고 한다.
특징으로는 Map의 key와 Set의 value로는 오로지 객체만 받을 수 있으며 기존의 Map과 Set와 다르게 일부 메서드만 존재한다고 한다.