원칙적으로 말하면 불가능하다. 이는 누구나 아는 사실이다. Set은 집합을 나타내기 위한 자료형이기 때문에, 중복값이 나타나면 안된다. 하지만 중복되는 원소가 나타나는 현상을 발견했기 때문에 이 글을 찾아왔을 것 같다.
Set에 중복이 나타나는 상황은 언제일까?
이런 현상은 배열이나 객체와 같은 참조타입 데이터의 값을 Set에 넣을 때 발생한다. 이렇게만 말하면 잘 감이 안 잡히기 때문에 바로 예시를 들어보자.
const set = new Set();
const obj1 = { key: 'value' };
const obj2 = { key: 'value' };
set.add(obj1);
set.add(obj2); // obj1과 obj2는 값은 동일하지만 다른 객체 참조
console.log(set); // Set { { key: 'value' }, { key: 'value' } }
console.log(set.size); // 2
obj1과 obj2는 동일한 내용의 프로퍼티를 가지고 있다. 이 때 obj1과 obj2를 set에 추가하면 set에 동일한 원소가 나타난다.
const array1 = [1, 2, 3];
const array2 = [1, 2, 3];
const array3 = array1;
const set = new Set();
set.add(array1);
set.add(array2);
set.add(array3);
console.log(set); // Set { [ 1, 2, 3 ], [ 1, 2, 3 ] }
console.log(set.size); // 2
배열의 경우에도 동일한 상황이 발생한다. array1과 array2가 다른 배열이기 때문에 set에 넣을 수 있다. 한편 array3은 array1과 동일한 배열을 참조하기 때문에 array3의 값은 set에 넣어지지 않는다.
왜 이런 현상이 발생할까?
참조 타입과 값 타입에 대한 이해가 있다면 빠르게 이해할 수 있다. 우리가 데이터들은 참조타입과 값 타입 둘 중 하나의 형태로 정해진다.
참조 타입: 어떤 데이터의 주소를 저장. ex)객체, 배열
값 타입: 어떤 데이터의 값을 직접적으로 저장. ex) 원시 타입 자료형(숫자, 문자열, 불리언, null, undefined, Symbol)
위의 예시에서 obj1과 obj2, 그리고 array1과 array2는 참조타입이며 각 변수는 고유한 주소를 저장한다. Set은 이 주소들을 해쉬테이블을 이용하여 저장한다. 그래서 Set내부에 '동일한 것들이 저장되어 있는 것처럼' 보이는 것이다.
예를 들어 obj1이 1234, obj 2341 이라는 주소를 가지고 있다고 하면 Set 내부적으로는 {1234,2341}을 저장한 셈이다. 하지만 주소 1234, 2341이 가리키는 값들은 동일한 내용이기 때문에 { { key: 'value' }, { key: 'value' } }와 같이 저장되는 것이다.
최종 결론: Set에 동일한 내용을 가진 객체나 원소를 넣으면, 중복 원소라도 넣을 수 있다. 하지만 내부적으로 살펴보면 서로 다른 주소를 넣는 것이기 때문에 실제로 중복되는 것을 넣는 것은 아니다.
'Javascript 데이터 구조 & 알고리즘 공부' 카테고리의 다른 글
배열을 객체로, 객체를 배열로 만드는 방법 (0) | 2023.06.09 |
---|---|
배열이나 문자열 자르는 메소드: slice, substring, splice 정리 (0) | 2023.05.18 |