Map/Set
es2015에 새로 추가된 자료구조 중 자주 쓰이는 것이 Map과 Set이다.
Map은 객체와 유사하고 Set은 배열과 유사하다
Map과 Set 과 오브젝트 리터럴{}과 어레이 리터럴[]과 다른점은 무엇일까?
자바스크립트는 문제점이 하나의 기능에 자유도가 높다.
리터럴 객체{}만 해도 사용하는 사람마다 방법이 다양하다. 코드 분석 시 의도파악이 어려움
어떤 목적으로 사용했는지 잘 알 수 있도록 전문적인 객체를 만든 것.
Map : 키과 값을 저장하는 객체(=자료구조)
new 생성자로 생성
Map : 1:1관계로 묶여있다.
일반 {}객체와 다른점은 객체를 키로 가능하다는 점이다.
객체를 키로 사용시 주의할 점 : 키가 되는 객체를 변수에 담에 사용해야 함.
// { a : 'b'} !== {a : 'b'} // true // 하단에 자세히 설명
// let obj = { a : 'b'}
// m.set(obj, 123)
// m.get(obj) // 123
Map의 사용 예시들을 알아보자
const m = new Map();
m.set('a', 'b'); // set(키, 값)으로 Map속성에 추가
m.set(3,'c'); // 문자열이 아닌 값을 키로 사용 가능
const d = {};
m.set(d, 'e') // 객체도 키값으로 가능
console.log(m); // Map(3) {size: 3, a => b, 3 => c, {} => e}
m.get(d); // get(키)로 속성값 조회
console.log(m.get(d)); // e
m.size; // size로 속성갯수 조회
console.log(m.size); // 3
// 객체 내 반복문 사용
const obj2 = {}
for (let i in obj2){
if(obj2.hasOwnProperty(i)){
obj2[i]; // 문제 : 포로토타입에 있는 속성까지 나옴. 해서 해즈오운프로퍼티 사용.
}
}
// 개선되어 사용할 수 있는 객체 내 반복문
for(const [k,v] of m){
console.log(k,v); // 속성간에 순서도 보장
}
m.forEach((v,k) => { // forEach도 가능
console.log(k,v) // 위와 값 가음
});
m.has(d); // has(키)로 속성 존재 여부 확인
console.log(m.has(d)); // true
m.delete(d) // delete(키)로 속성을 삭제
m.clear() // 전부 제거
console.log(m.size); // 0
Map은 속성들간의 순서를 보장하고 반복문을 사용할 수 있다
속성명으로 문자열이 아닌 값을 사용할 수 있고 size 메서드를 통해 속성의 수를 쉽게 알 수 있다는 점에서 일반 객체와 다르다.
Set
Set은 배열을 완전 대체하기 어렵다.
Set은 중복을 허용하지 않는다.
따라서 배열 구조를 사용하고 싶으나 중복을 허용하고 싶지 않을 때 사용하면 된다.
또는 기존 배열에서 중복을 허용하고 싶지 않을 때 Set을 사용한다.
자료형이 다르면 들어간다 1과 '1'
Set의 사용 예시를 알아보자.
const s = new Set();
s.add(false); // add(요소)로 Set에 추가
s.add(1);
s.add('1');
s.add(1); // 중복이므로 무시됨
s.add(2);
console.log(s.size) // 4
s.has(1) // has(요소)로 요소 존재 여부를 확인
console.log(s.has(1)); // true
for(const a of s ){
console.log(a); // false 1 '1' 2
}
s.forEach((a)=>{
console.log(a) // false 1 '1' 2
})
// 배열에서 중복을 제거하고 싶을 때 예시
const arr = [1,2,3,2,3,5,2];
const s2 = new Set(arr)
console.log(s2); // {1 2 3 5}
const s3 = Array.from(s2)
console.log(s3); // [1 2 3 5]
{ a : 'b'} !== {a : 'b'} // true 인 이유
객체의 경우 객체의 참조값 즉 객체가 저장된 주소값을 비교하기 때문에 true가 나온다.
원시타입(Primitive type)의 경우 변수에 그 값 자체를 저장하고 복사하기 때문에
let a =2; // let b=2 // a=b true 를 반환하는 것이다.
객체를 변수에 저장될 때는 객체의 값이 아닌 객체가 저장되어 있는 메모리 주소가 저장되는데
한 주소에는 한 객체만 저장되니 주소가 다르다고 나오는 것이다.
왼쪽 객체는 a동 메모리, 오른쪽 객체는 b동 메모리에 저장된다.
객체를 비교하면 저장된 주소를 비교하기에 a동과 b동을 비교
let obj1 = { a: 'b' };
let obj2 = obj1;
obj2.a = 'c';
let obj3 = { a: 'b' };
console.log(obj1 === obj3); // false
obj3.a = 'c';
console.log(obj1 === obj3); // false
obj3 = obj2;
console.log(obj1 === obj3); // true