JS - new Set() & new Map()

sarang_daddy·2022년 12월 3일
0

Javascript

목록 보기
7/26

객체와 배열은 아래와 같은 특징을 가지고 있다.

  • 객체 : 키가 있는 컬렉션을 저장함
  • 배열 : 순서가 있는 컬렉션을 저장함

객체와 배열이 가지고 있는 특징만으로 현실 세계를 반역하기에 어려움이 많아 Set과 Map이 등장했다.

new Set()

Set의 기능

: 유니크한 배열 만들기.
배열은 중복을 허락하면서 원하는 모든 값을 넣을 수 있다.
하지만 Set은 유니크한 값만 넣을 수 있다.

중복없이 유일한 값을 저장하려고 할때, 이미 존재하는지 체크할 때 유용하다.

let mySet = new Set();

mySet.add("Sarang");
mySet.add("Sojin");
mySet.add("Sarang");

mySet.forEach((v) => console.log(v));
// Sarang, Sojin (중복된 "Sarang" 은 하나만 나온다.)

console.log(mySet.has("Sarang"));
// true (.has를 이용하여 존재 체크 가능하다.)

mySet.delete("Sarang");
mySet.forEach((v) => console.log(v));
// Sojin (.delete를 이용하여 삭제가 가능하다.)
const set = new Set([1, 2, 3]);

for (const value of set) {
  console.log(value); 
  // 1 2 3
  // Set 객체는 for...of 문으로 순회할 수 있다.
}

console.log([...set]); 
// [1, 2, 3]
// Set 객체는 스프레드 문법의 대상이 될 수 있다.

const [a, ...rest] = [...set];
console.log(a, rest); 
// 1, [2, 3]
// Set 객체는 배열 디스트럭처링 할당의 대상이 될 수 있다.

Set의 활용

추가학습자료
1. Set을 사용한 배열의 중복 요소 제거

const uniq = array => [...new Set(array)];
console.log(uniq([2, 1, 2, 3, 4, 3, 4])); 
// [2, 1, 3, 4]
  1. 교집합
const setA = new Set([1, 2, 3, 4]);
const setB = new Set([2, 4]);

Set.prototype.intersection = function (set) {
  return new Set([...this].filter(v => set.has(v)));
};

// setA와 setB의 교집합
console.log(setA.intersection(setB)); 
// Set(2) {2, 4}

// setB와 setA의 교집합
console.log(setB.intersection(setA)); 
// Set(2) {2, 4}
  1. 합집합
const setA = new Set([1, 2, 3, 4]);
const setB = new Set([2, 4]);

Set.prototype.union = function (set) {
  return new Set([...this].filter(v => set.add(v)));
};

// setA와 setB의 합집합
console.log(setA.union(setB)); 
// Set(4) {1, 2, 3, 4}

// setB와 setA의 합집합
console.log(setB.union(setA)); 
// Set(4) {2, 4, 1, 3}
  1. 차집합
const setA = new Set([1, 2, 3, 4]);
const setB = new Set([2, 4]);

Set.prototype.difference = function (set) {
  return new Set([...this].filter(v => !set.has(v)));
};

// setA에 대한 setB의 차집합
console.log(setA.difference(setB)); 
// Set(2) {1, 3}

// setB에 대한 setA의 차집합
console.log(setB.difference(setA)); 
// Set(0) {}
  1. 부분집합과 상위집합
const setA = new Set([1, 2, 3, 4]);
const setB = new Set([2, 4]);

Set.prototype.isSuperset = function (subset) {
  const supersetArr = [...this];
  return [...subset].every(v => supersetArr.includes(v));
};

// setA가 setB의 상위 집합인지 확인한다.
console.log(setA.isSuperset(setB)); 
// true

// setB가 setA의 상위 집합인지 확인한다.
console.log(setB.isSuperset(setA)); 
// false

Set을 이용한 로또 번호 생성하기

const SETTING = {
  name: "LUCKY LOTTO!",
  count: 6,
  maxNumber: 45,
};

const { count, maxNumber } = SETTING;
// destructuring을 이용하여 필요 값만 사용

function getRandomNumber(count, maxNumber) {
  let numberArray = [];
  for (let i = 1; i <= maxNumber; i++) {
    numberArray.push(i);
  }

  let set = new Set();
  while (set.size <= count - 1) {
    let randomNumber = Math.floor(Math.random() * maxNumber + 1);
    set.add(randomNumber);
  } 
  // 중복값을 제외하는 Set의 기능을 이용하여 6개의 Size를 채워준다.

  set.forEach((v) => console.log(v));
  console.log(set.values());
}

getRandomNumber(count, maxNumber);

WeakSet()

객체 형태(만)를 중복없이 저장하려고 할때 유용하다.

  • 참조를 가지고 있는 객체만 저장이 가능하다.
let ws = new WeakSet();
let arr = [1, 2, 3, 4];

ws.add(arr);
console.log(ws);
// WeakSet {Array(4)}

ws.add("111");
ws.add(111);
ws.add(null);
console.log(ws);
// Error : Invalid value used in weak set

ws.add(function () {});
console.log(ws);
// WeakSet {Array(4), ƒ}
  • 가비지 콜렉션 (참조를 가지고 있는 객체가 아닌 값) 자동 제거 해준다.
let ws = new WeakSet();

let arr = [1, 2, 3, 4];
let arr2 = [5, 6, 7, 8];
let obj = { arr, arr2 };

ws.add(arr);
ws.add(arr2);
ws.add(obj);
console.log(ws);
// WeakSet {Array(4), Array(4), {arr:Array(4), arr2:Array(4)}}

arr = null;
console.log(ws);
// WeakSet {Array(4), Array(4), {arr:Array(4), arr2:Array(4)}}

console.log(ws.has(arr), ws.has(arr2));
// false true
// 가비지가 된 arr을 has하고 있지 않다고 나온다.

new Map()

Map의 기능

Set과 유사하지만 ket & value를 함께 사용 한다는 점에서 차이가 있다.
(Set은 value만 사용 즉, Set은 배열에 많이 사용되고 Map은 객체에 많이 사용된다.)

<맵의 주요 메서드>
new Map() – 맵을 만듭니다.
map.set(key, value) – key를 이용해 value를 저장합니다.
map.get(key) – key에 해당하는 값을 반환합니다. key가 존재하지 않으면 undefined를 반환합니다.
map.has(key) – key가 존재하면 true, 존재하지 않으면 false를 반환합니다.
map.delete(key) – key에 해당하는 값을 삭제합니다.
map.clear() – 맵 안의 모든 요소를 제거합니다.
map.size – 요소의 개수를 반환합니다.

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'

// 키로 객체도 허용한다.
let john = { name: "John" };
// 고객의 가게 방문 횟수를 세본다고 가정해 봅시다.
let visitsCountMap = new Map();
// john을 맵의 키로 사용하겠습니다.
visitsCountMap.set(john, 123);
alert( visitsCountMap.get(john) ); // 123

객체는 키를 문자형으로 변환한다.
맵은 키의 타입을 변환시키지 않고 그대로 유지한다.

Map의 활용

map.keys() – 각 요소의 키를 모은 반복 가능한(iterable, 이터러블) 객체를 반환합니다.
map.values() – 각 요소의 값을 모은 이터러블 객체를 반환합니다.
map.entries() – 요소의 [키, 값]을 한 쌍으로 하는 이터러블 객체를 반환합니다. 이 이터러블 객체는 for..of반복문의 기초로 쓰입니다.

let recipeMap = new Map([
  ['cucumber', 500],
  ['tomatoes', 350],
  ['onion',    50]
]);

// 키(vegetable)를 대상으로 순회합니다.
for (let vegetable of recipeMap.keys()) {
  alert(vegetable); // cucumber, tomatoes, onion
}

// 값(amount)을 대상으로 순회합니다.
for (let amount of recipeMap.values()) {
  alert(amount); // 500, 350, 50
}

// [키, 값] 쌍을 대상으로 순회합니다.
for (let entry of recipeMap) { // recipeMap.entries()와 동일합니다.
  alert(entry); // cucumber,500 ...
}

WeakMap()

WeakSet과 마찬가지로 Map의 기능에서 참조를 가지고 있는 객체만을 다룬다.

let wm = new WeakMap();
let myFun = function () {};

wm.set(myFun, 0); // key : myFun value : 0
console.log(wm);
// WeakMap {ƒ => 0}

let count = 0;
for (let i = 0; i < 10; i++) {
  count = wm.get(myFun); // key myFun의 value값 0
  count++;
  wm.set(myFun, count);
}

console.log(wm.get(myFun));
// 10

myFun = null; // myFun을 함수에서 null로 변경
console.log(wm.get(myFun));
// undefined

참조 사이트 1
참조 사이트 2
모던 자바스크립트 Deep Dive

profile
한 발자국, 한 걸음 느리더라도 하루하루 발전하는 삶을 살자.

0개의 댓글