반응형
Jake Seo
제이크서 위키 블로그
Jake Seo
전체 방문자
오늘
어제
  • 분류 전체보기 (715)
    • 일상, 일기 (0)
    • 백준 문제풀이 (1)
    • 릿코드 문제풀이 (2)
    • 알고리즘 이론 (10)
      • 기본 이론 (2)
      • 배열과 문자열 (8)
    • 데이터베이스 (15)
      • Planet Scale (1)
      • MSSQL (9)
      • 디비 기본 개념 (1)
      • SQLite 직접 만들어보기 (4)
    • 보안 (7)
    • 설계 (1)
    • 네트워크 (17)
      • HTTP (9)
      • OSI Layers (5)
    • 회고 (31)
      • 연간 회고 (2)
      • 주간 회고 (29)
    • 인프라 (52)
      • 도커 (12)
      • AWS (9)
      • 용어 (21)
      • 웹 성능 (1)
      • 대규모 서비스를 지탱하는 기술 (9)
    • 깃 (7)
    • 빌드 도구 (7)
      • 메이븐 (6)
      • 그레이들 (0)
    • Java (135)
      • 이펙티브 자바 (73)
      • 자바 API (4)
      • 자바 잡지식 (30)
      • 자바 디자인 패턴 (21)
      • 톰캣 (Tomcat) (7)
    • 프레임워크 (64)
      • next.js (14)
      • 스프링 프레임워크 (28)
      • 토비의 스프링 (6)
      • 스프링 부트 (3)
      • JPA (Java Persistence API) (5)
      • Nest.js (8)
    • 프론트엔드 (48)
      • 다크모드 (1)
      • 노드 패키지 관리 매니저 (3)
      • CSS (19)
      • Web API (11)
      • tailwind-css (1)
      • React (5)
      • React 새 공식문서 요약 (1)
      • HTML (Markup Language) (5)
    • 자바스크립트 (108)
      • 모던 자바스크립트 (31)
      • 개념 (31)
      • 정규표현식 (5)
      • 코드 스니펫 (1)
      • 라이브러리 (6)
      • 인터뷰 (24)
      • 웹개발자를 위한 자바스크립트의 모든 것 (6)
      • 팁 (2)
    • Typescript (49)
    • 리눅스와 유닉스 (10)
    • Computer Science (1)
      • Compiler (1)
    • IDE (3)
      • VSCODE (1)
      • IntelliJ (2)
    • 세미나 & 컨퍼런스 (1)
    • 용어 (개발용어) (16)
      • 함수형 프로그래밍 용어들 (1)
    • ORM (2)
      • Prisma (2)
    • NODEJS (2)
    • cypress (1)
    • 리액트 네이티브 (React Native) (31)
    • 러스트 (Rust) (15)
    • 코틀린 (Kotlin) (4)
      • 자바에서 코틀린으로 (4)
    • 정규표현식 (3)
    • 구글 애널리틱스 (GA) (1)
    • SEO (2)
    • UML (2)
    • 맛탐험 (2)
    • 리팩토링 (1)
    • 서평 (2)
    • 소프트웨어 공학 (18)
      • 테스팅 (16)
      • 개발 프로세스 (1)
    • 교육학 (1)
    • 삶의 지혜, 통찰 (1)
    • Chat GPT (2)
    • 쉘스크립트 (1)
    • 컴파일 (2)
    • Dart (12)
    • 코드팩토리의 플러터 프로그래밍 (4)
    • 플러터 (17)
    • 안드로이드 스튜디오 (1)
    • 윈도우즈 (1)
    • 잡다한 백엔드 지식 (1)
    • 디자인 패턴 (1)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 느린 쿼리
  • 싱글턴
  • 외래키 제약조건
  • 빈 검증
  • 슬로우 쿼리
  • 이펙티브 자바
  • 메이븐 라이프사이클
  • item7
  • 자바 검증
  • 서버리스 컴퓨팅
  • prerendering
  • item9
  • 추상 팩터리 패턴
  • Pre-rendering
  • next js app
  • 스프링 검증
  • 자바
  • Javadoc 자바독 자바주석 주석 Comment
  • 팩터리 메서드 패턴
  • 토비의 스프링
  • 플라이웨이트패턴
  • 메이븐 페이즈
  • 러스트
  • bean Validation
  • MSSQL
  • 작업기억공간
  • 이펙티브 자바 item9
  • 자바스크립트 면접
  • NEXT JS
  • 자바스크립트
  • 프로그래머의 뇌
  • Java
  • 참조 해제
  • 자바 디자인패턴
  • 객체복사
  • 도커공식문서
  • 자료구조
  • pnpm
  • 알고리즘
  • try-with-resources
  • 메이븐 골
  • Next.js
  • 싱글톤
  • 이펙티브자바
  • rust
  • 싱글톤 패턴
  • item8
  • 디자인패턴
  • serverless computing
  • 자바스크립트 인터뷰

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
Jake Seo

제이크서 위키 블로그

자바스크립트/모던 자바스크립트

모던 자바스크립트, 맵 (Map)

2023. 3. 23. 21:39

맵이란?

  • 키/밸류 쌍을 저장한다.
    • 이 쌍을 합쳐서 엔트리라고도 한다.
    • 그래서 엔트리들을 저장한다고도 할 수 있다.

가끔 Map 자료구조가 적합한 곳에 오브젝트를 대신 사용하는데, 이는 좋지 않은 선택이다.
참고자료: Object 와 Map 의 차이

Map 의 탄생

  • ES2015+ 에서 맵(Map), 셋(Set), 위크맵(WeakMap), 위크셋(WeakSet) 이 생겼다.
  • Set 은 중복되지 않은 값의 집합을 저장한다.
  • 위크맵은 키가 객체이고 객체의 참조(strong reference)가 사라지면 가비지콜렉트된다.
  • 위크셋은 위크맵의 Set 버전이다.

Map 의 기본 메서드

  • set(): 값을 설정할 때 사용한다.
  • clear(): 맵의 모든 엔트리를 삭제할 때 사용한다.
  • delete(): 하나의 엔트리를 삭제할 때 사용한다.
  • has(): 해당 키가 있는지 확인할 때 사용한다.
  • get(): 해당 키에 대응하는 value 를 얻을 때 사용한다.
  • keys(): 모든 키를 MapIterator 형태로 얻는다.
  • entries(): 키 밸류를 엔트리 형태로 얻는다.
  • forEach(): forEach 형태로 순회한다.
  • size: 내부에 몇개의 값이 있는지 알려준다.

Map 의 메서드는 이름이 너무 명확해서 이름만 봐도 기능을 알기 쉽다.
더 자세한 설명이 필요하다면 공식문서 에서 보자.

Map 과 Object 의 용도 차이 알아보기

  • 사실 자바스크립트의 일반 객체를 사용해도 키, 값을 매칭하는 형식으로 사용은 가능하다.
  • 그러나 Map 은 기존 자바스크립트 일반 객체와 비교되는 확연한 특징이 있다.

키의 타입 (Type of keys)

  • Object 는 키에 문자열이나 심볼만 넣을 수 있다.
  • Object.prototype 내부에 있는 프로퍼티를 키의 이름으로 지정하는 경우 프로토타입 사용이 힘들다.
  • Map 은 모든 타입을 다 키로 지정할 수 있다.
// prettier-ignore
const obj = {
  0: "a",
  "0": "b"
};

const map = new Map();
map.set(0, "a");
map.set("0", "b");

console.log(obj[0]); // b
console.log(obj["0"]); // b
console.log(obj[0] === obj["0"]); // true

console.log(map.get(0)); // a
console.log(map.get("0")); // b
console.log(map.get(0) === map.get("0"));
  • obj 의 경우, 문자열 "0" 과 숫자 0 타입을 구분해서 키로 지정할 수 없는 것을 볼 수 있다.
  • map 의 경우, 문자열 "0" 과 숫자 0 타입을 구분하여 키로 지정할 수 있다.

순회 (Iteration)

  • Object 는 순서가 때때로 뒤죽박죽이다.
    • 몇몇 케이스(ex.숫자와 문자를 동시에 키로 이용하는 경우)에 삽입한 순서를 유지하지 못한다.
  • Map 은 타입에 관계 없이 삽입한 순서를 유지한다.
    • 삭제했다가 다시 넣으면 순서가 맨 뒤로 간다.
    • 단순 값 업데이트 시에는 순서가 변화하지 않는다.
  • Object 는 자체적으로 Iterator 를 제공하지도 않는다.
const obj = {};
obj["a"] = "hello";
obj[0] = "world";

for (const [k, v] of Object.entries(obj)) {
  console.log(k, v);
  /* 
  출력결과:
  0 world
  a hello
  */
}
// 출력결과 삽입한 순서가 아니다.

const map = new Map();
map.set("a", "hello");
map.set(0, "world");

for (const [k, v] of map) {
  console.log(k, v);
  /*
  출력결과:
  a hello
  0 'world'
  */
}
// 출력결과 삽입한 순서를 지킨다.

최적화 (Optimization)

  • Object 는 속성이 추가/업데이트 되며 제거되지 않는다는 가정하에 최적화된다.
  • Map 은 사용 사례가 다르게 적용되기 때문에 다른 방법으로 최적화된다.

키 값 존재 확인

키에 대응하는 값으로 해당 키가 존재하는지 확인할 때 둘은 약간의 차이가 있다.

  • Object 는 키에 대응하는 값으로 falsy 한 것이 들어있을 때 실수하기 쉽다.
  • Map 은 키에 대응하는 값으로 falsy 한 값이 있어도 has() 메서드를 통해 확실히 확인이 가능하다.
const obj = {
  a: 0,
};

const map = new Map();
map.set("a", 0);

if (obj.a) {
  console.log("obj 에 키 a 존재");
}

if (map.has("a")) {
  console.log("map 에 키 a 존재");
}

/*
출력 결과:
map 에 키 a 존재
*/
  • 값이 falsy 하기 때문에 if(obj.a) 조건이 충족되지 않는다.

사이즈 확인

  • Object 는 enumerable 한 프로퍼티를 세는데 부가적인 작업이 든다.
  • Map 은 Map.size 로 한번에 확인이 가능하다.

Map 에서 주의할만한 특성

Object 는 주소값을 기준으로 구분한다.

  • Object 를 키로써 활용할 수 있는 반면, 속성이 같은 Object 여도 주소값이 다르기 때문에 매 Object 가 다른 키가 된다.

get 은 두가지 상황에서 undefined 를 반환한다.

  • 키에 대해 일치하는 엔트리가 없거나 엔트리가 존재하지만 값이 undefined 인 경우이다.
  • 그래서 존재를 확인할 때는 has() 메서드를 이용해야 한다.

키 동등성으로 SameValueZero 를 이용한다.

SameValueZero 에 대한 설명은 여기서 확인할 수 있다.

  • 간단하게 표현하자면 === 와 동일한데, NaN 의 동등 비교가 가능하다
    • +0, -0 에 대한 처리도 === 와 동일하다.

Map 은 Iterable 이다.

  • Map 은 for-of 와 같은 iterator 를 사용하는 문법에서 반복 가능하다.
const m = new Map();
m.set("a", "apple");
m.set("b", "blue");
m.set("c", "chrome");

for (const e of m) {
  console.log(e);
}

/*
출력결과:
(2) ['a', 'apple']
(2) ['b', 'blue']
(2) ['c', 'chrome']
*/

m.forEach((value, key) => {
  console.log(`${key} => ${value}`);
});

/*
출력결과:
a => apple
b => blue
c => chrome
*/

엔트리의 배열을 이용해 맵 생성하기

  • 엔트리란 [key, value] 형태의 자료구조를 말한다.
  • 엔트리의 배열을 new Map() 생성자에 넣어 Map 객체를 생성할 수 있다.
  • API 에서 JSON 엔트리의 배열 형태로 응답을 받으면 바로 Map 생성자를 통해 Map 을 만들어낼 수 있다.
  • API 에서 JSON 오브젝트 형태로 받았다면, Object.entries() 를 이용해서 바로 Map 을 만들 수 있다.
const m = new Map([
  ["one", "uno"],
  ["two", "due"],
  ["three", "tre"],
]);

for (const e of m) {
  console.log(e);
}

/*
출력 결과:
(2) ['one', 'uno']
(2) ['two', 'due']
(2) ['three', 'tre']
*/

const m2 = new Map(
  Object.entries({
    one: "uno",
    two: "due",
    three: "tre",
  })
);

for (const e of m2) {
  console.log(e);
}

/*
출력 결과:
(2) ['one', 'uno']
(2) ['two', 'due']
(2) ['three', 'tre']
*/

사실 Map.prototype.entries() 와 Map.prototype[Symbol.iterator] 는 동일한 함수를 참조한다.

맵의 서브클래스 활용해보기

  • 맵을 서브클래스로 이용하면 강력한 커스텀 맵을 만들어내는 것이 가능하다.
class MyMap extends Map {
  filter(predicateFn, thisArg) {
    const newMap = new (this.constructor[Symbol.species] || MyMap)();
    for (const [key, value] of this) {
      if (predicateFn.call(thisArg, key, value, this)) {
        newMap.set(key, value);
      }
    }

    return newMap;
  }
}

const m = new MyMap([
  ["one", "uno"],
  ["two", "due"],
  ["three", "tre"],
]);

const filteredMap = m.filter((key) => key.includes("t"));

for (const [key, value] of filteredMap) {
  console.log(`${key} => ${value}`);
}

/*
출력결과:
two => due
three => tre
*/

자신의 인스턴스를 얻기 위해 new this.constructor[Symbol.species] 를 활용한 것을 볼 수 있다.

Map 의 성능

  • 당연히 일반 객체보다 좋다.
  • 스펙상 'O(1)의 접근 시간을 사용하는 해시 테이블 또는 기타 매커니즘을 사용하여 구현해야 한다.' 라고 정의되어 있기 때문에 어떤 JS 엔진에서도 빠르다.
  • 아래 코드보다 빨라야 한다.
if (!array.some((e) => e.key === key)) {
  array.push({ key, value });
}
반응형
저작자표시 비영리 (새창열림)

'자바스크립트 > 모던 자바스크립트' 카테고리의 다른 글

모던 자바스크립트, 위크 맵(WeakMap) 과 위크 셋(WeakSet)  (0) 2023.03.24
모던 자바스크립트, 셋 혹은 세트 (Set)  (0) 2023.03.23
모던 자바스크립트, 4가지 동등성 비교 알고리즘  (0) 2023.03.22
모던 자바스크립트, Reflect (리플렉트) 객체란?  (0) 2023.03.20
모던 자바스크립트, TypedArray (타입이 있는 배열)  (0) 2023.03.19
    '자바스크립트/모던 자바스크립트' 카테고리의 다른 글
    • 모던 자바스크립트, 위크 맵(WeakMap) 과 위크 셋(WeakSet)
    • 모던 자바스크립트, 셋 혹은 세트 (Set)
    • 모던 자바스크립트, 4가지 동등성 비교 알고리즘
    • 모던 자바스크립트, Reflect (리플렉트) 객체란?
    Jake Seo
    Jake Seo
    ✔ 잘 보셨다면 광고 한번 클릭해주시면 큰 힘이 됩니다. ✔ 댓글로 틀린 부분을 지적해주시면 기분 나빠하지 않고 수정합니다. ✔ 많은 퇴고를 거친 글이 좋은 글이 된다고 생각합니다. ✔ 간결하고 명료하게 사람들을 이해 시키는 것을 목표로 합니다.

    티스토리툴바