[JavaScript] Map과 Set, WeakMap과 WeakSet

고병표·2022년 4월 18일
0

JavaScript

목록 보기
7/9
post-thumbnail

Map 자료구조

  • Map은 ES6에서 값을 매핑하기 위한 새로운 데이터 구조
  • Object는 전통적으로 문자열 값을 매핑하는데 사용, 키를 값으로 설정 + 값을 검색 + 키를 삭제 + 키에 저장된 내용을 검색 가능하게 + 키는 모두 string + 크기를 수동으로 추적

Map의 키는 모든 값을 가질 수 있다. 크기를 쉽게 얻을 수 있고, 삽입된 순서대로 반복

언제 사용할까?

  • 실행 시까지 키를 알수 없고, 모든 키가 동일한 type이며 모든 값들이 동일한 type일 경우에는 objects를 대신해서 map을 사용

  • 각 개별 요소에 대해 적용해야 하는 로직이 있을 경우에는 objects를 사용

WeakMap

WeakMap은 키로 오직 Object 타입만 사용할 수 있습니다. Symbol과 같은 원시 값은 WeakMap의 키로 사용할 수 없습니다.

내장 WeakMap은 키 객체의 "약한" 참조만 가지고 있습니다. 따라서 내장 WeakMap은 가비지 컬렉션을 방지하지 않으며, 가비지 컬렉션 시 키 참조 역시 사라집니다. 맵 내의 값 역시 "약한" 참조로서 가비지 컬렉션을 막지 않습니다. WeakMap은 키가 가비지 컬렉션 되지 않았을 때만 가치가 있는 정보를 키와 연결할 때 특히 유용한 구조입니다.

  • 약한 참조로 인해 WeakMap의 키는 열거할 수 없다. (키 목록을 가져오는 메서드는 존재하지 않습니다.)
  • 그런 메서드가 존재한다면 그 구현은 가비지 컬렉션 상태에 의존하게 되므로 비결정적인 결과가 발생
  • 키의 목록이 필요하면 Map을 사용

Set 자료구조

  • 객체는 값들의 집합이다. 입력된 순서에따라 저장된 요소를 반복처리할 수 있다. Set은 중복된 값을 허용하지 않는다. 따라서 특정 값은 Set내에서 하나만 존재 하게 된다.

  • 일반 배열에 비해 사용 이점

  • indexOf 메서드를 사용하여 배열내에 특정 요소가 존재하는지 확인하는 것은 느리다.

  • 배열에선 해당 요소를 배열에서 잘라내야 하는 반면 Set객체는 요소의 값으로 해당 요소를 삭제하는 기능 제공한다. (has, delete, add) (여러 타입 add 가능)

  • NaN은 배열에서 indexOf메서드로 찾을 수 없다.

  • Set객체는 값의 유일성을 보장하기 때문에 직접 요소의 중복성을 확인할 필요가 없다.

WeakSet

객체는 객체를 저장하는 일종의 집합이다. WeakSet내의 중복된 객체는 없으며 WeakSet내의 요소를 열거할 수는 없다.

Set과 가장 큰 차이점은 Set과는 다르게 WeakSet은 객체의 집합이며 객체만 저장할 수 있다. 특정 type의 값을 저장할 수는 없다.

WeakSet은 약한 참조를 가진다. WeakSet내의 객체에 대한 참조는 약하게 연결이 되어 있다. WeakSet내에 저장되어 있는 객체에 대한 참조가 없게되면 garbage collection 대상이되어 수거 된다.

따라서 현재 저장되어 있는 객체에 대한 목록은 없으며 WeakSet은 열거형이 아님

Set,Map 자료구조 순회하기

1. forEach 메서드로 순회하기

MapSet에서의 forEach( [Map or Set].prototype.forEach )는 Array의 forEach( Array.prototype.forEach )와 비슷하지만 조금 다릅니다.

Array의 forEach가 받는 콜백함수의 인수는 순서대로 인덱스배열 순으로 들어옵니다. 하지만 MapSet에서의 forEach가 받는 콜백함수의 인수는 순서대로 오브젝트(Map or Set) 로 들어옵니다.

Set의 콜백함수는 key 대신에 value2가 들어옵니다. value2는 value와 똑같습니다. 아래의 예시와 "개별 값으로 순회 하기" 설명을 확인해주세요.

    // JavaScript
    const map = new Map();
    const set = new Set();
    // TypeScript
    const map = new Map<string, string>();
    const set = new Set<string>();
    
    map.set('name', 'Mommoo');
    map.set('age' , 'secret');
    
    set.add('Mommoo');
    set.add('secret');
    map.forEach((value, key, mapObject) => console.log(key +' , ' +value));
    // name , Mommoo
    // age , secret
    set.forEach((value1, value2, setObject) => console.log(value1 +' , '+ value2));
    // Mommoo , Mommoo
    // secret , secret

2. for.. of 문법으로 순회하기

forEach 방법은 순회 중간에 continuebreakreturn 과 같은 루프 기능을 못쓰지만,ES6(ES2015)에서 새로나온 for.. of 문법을 사용하면, 가능합니다. Map의 for.. of로 호출되는 값은 와 벨류가 들어가 있는 배열 입니다. Set의 for.. of로 호출되는 값은 벨류입니다.

    const map = new Map();
    const set = new Set();
    map.set('name', 'Mommoo');
    map.set('age' , 'secret');
    set.add('Mommoo');
    set.add('secret');
    
    for ( let item of map ) {
    	console.log(item[0] +' , '+ item[1]);
    }
    // name , Mommoo
    // age , secret
    for ( let item of set ) {
    	console.log(item);
    }
    // Mommoo
    // secret

TypeScript는 조금 까다롭습니다. 이유는 Iterable 속성 때문인데요. type iterable 속성때문에 for.. of 가 컴파일이 되질 않습니다.

0개의 댓글