과거에 나는 어떻게 사용해 왔는가 🐣

youseock·2024년 2월 5일
0

[JS] Map vs Object

목록 보기
2/5

Deep Dive하기 전에 내가 Map{ } 를 어떻게 사용해 왔고, 얼마나 알고 있는지 확인해보자

여태 Map과 Object를 어떻게 사용해왔는가

자바스크립트에는 key ,value 쌍으로 이루어진 데이터를 묶어서 다루는 데이터 형식으로 { }Map 이 있다. { }Map 은 몇 몇 차이를 가지고 있지만, key, value를 저장하는 컬렉션으로 사용할 때는 크게 차이점을 느끼지 못 했다. 보통 해당 키 값을 반복적으로 업데이트 해야 한다면 { } 를 사용했는데, 그 이유는 단순히 코드가 짧아서 이다.

💡 { } 를 key, value 값을 저장하는 자료구조라고 엄밀하게 부르고 싶을땐, 리터럴 객체라는 단어로 명명하는 편인데, 그 이유는 아래와 같다.

typeof [] === 'object' // true
typeof null === 'object' // true
typeof {} === 'object' // true
// typeof 연산자는 피연산자의 타입을 스트링으로 리턴한다.
// 리턴하는 타입은 원시타입이다.
// []은 실제로 object가 맞다. 🔆

자바스크립트에서 객체는 포괄적인 의미를 갖는다.
객체를 만드는 방법은 여러가지 있지만, 그 중에 리터럴 객체를 이용하는 것이 가장 보편적인 방법이라 리터럴 객체라고 부르는 편이다.

 	const literalObj = {
		love :'JavaScript';
	};    
    const obj = new Object();
	obj.love = 'JavaScript';
	// key:value를 집어넣기 힘들다.
    const obj = Object.create(literalObj);
	// deep copy할 목적이 아니라면 Object.create를 사용할 이유가 없어 보인다.		

간단한 예시로 Object와 Map를 비교하자

상황 설명 : items 배열에 item들이 저장되어 있고, 해당 item의 숫자를 세어 저장하고자 한다.
items = ['a','b','a','c'] => a:2,b:1,c:1

Map

const myMap = new Map();

for (const item of items) {
  myMap.has(item) 
  ? myMap.set(item, myMap.get(item) + 1) 
  : myMap.set(item, 1);
}

{ }

const myObj = {};

for (const item of items) {
  myObj[item] = myObj[item] ? myObj[item] + 1 : 1;
}

{ } 를 사용해서 key, value 쌍을 저장하는 코드가 짧다는 것을 확인할 수 있다. 물론, Map 을 사용하는 경우도 있다. { } 의 경우 입력한 key 순서를 보장하지 못 한다. 심지어 { } 는 직접적으로 순회할 수도 없다. 이터러블하지 않기 때문이다. { } 를 순회하기 위해선 이터러블 객체를 반환하는 메서드인 Object.keys, Object.values, Object.entries를 사용해 이터러블을 반환한 후에 순회가 가능하다.

이터러블을 간단히 알아보자

❓ 해당 데이터가 이터러블한 지 확인하는 방법

Symbol.iterator in map // true
Symbol.iterator in {} // false

❓ 이터러블 하다면 뭐가 가능할까

  • for .. of 문으로 순회
  • 스프레드 연산자 사용 가능
  • 구조분해 할당 가능

사용 예시

const coin1 = ["이더리움", "300만원"];
const coin2 = ["비트코인", "6000만원"];
const coinMap = new Map([coin1, coin2]);

// for .. of 문으로 순회
for (const coinInfo of coinMap){...}

// 스프레드 연산자 사용 가능
const coinMapArr = [...coinMap];
console.log(coinMapArr)
// [ [ '이더리움', '300만원' ], [ '비트코인', '6000만원' ] ]

// 구조분해 할당 가능
for (const [coinName,coinPrice] of coinMap){...}

순회하는 방법으로 Object와 Map를 비교하자

순회하기 전 key, value 저장하는 로직

const items = [4,3,2,1];

const myMap = new Map();
for (const item of items) {
  myMap.has(item) ? myMap.set(item, myMap.get(item) + 1) : myMap.set(item, 1);
};

const myObj = {};
for (const item of items) {
  myObj[item] = myObj[item] ? myObj[item] + 1 : 1;
};

{ }의 순회

Object.keys(myObj);
// [ '0', '1', '2', '3' ]
  • 순서가 보장되지 않는다.

Map의 순회

myMap.keys();
// [Map Iterator] { 4, 3, 2, 1 }
  • 순서가 보장된다.

key값의 타입으로 Object와 Map를 비교하자

Map 은 모든 값들을 key 로 가질 수 있는데 반해 { } 는 제한이 있다.
리터럴 객체는 string | number | symbol에 해당하는 값만 key로 가질 수 있다.

type keyTypes = keyof any; 
// keyTypes = string | number | symbol 

🔥주의할 점🔥 은 저장한 모든 key를 반환해서 사용할 수 없다는 점이다.
예시를 통해 알아보자

const 소중한심볼 = Symbol('없어지면큰일남');
const items = [소중한심볼,소중한심볼,소중한심볼];

const myMap = new Map();
for (const item of items) {
  myMap.has(item) ? myMap.set(item, myMap.get(item) + 1) : myMap.set(item, 1);
}

const myObj = {};
for (const item of items) {
  myObj[item] = myObj[item] ? myObj[item] + 1 : 1;
}

{ } 에 심볼을 key로 사용할 순 있지만, Key로 반환할 순 없다

Object.keys(myObj);
// []

Map은 가능하다.

myMap.keys();
// [Map Iterator] { Symbol(key) }
myMap.forEach((key)=>myMap.get(key));
// Symbol(key)를 key로 myMap.get(key)로 value를 꺼낼 수 있다.

💡 Object.keys는 이터러블 객체를 반환하지만 저장된 모든 key 값을 반환하는 것은 아니다. 주어진 객체의 열거 가능한 속성 중 문자열 로 된 속성 이름만 배열로 반환한다.
Object.values, Object.entries도 프로퍼티가 문자열인 경우만 해당 값을 반환한다.

결론

{ }Map 에 대해 기존에 알고 있던 사실들을 되짚어 보며, 어떤 경우에 뭘 선택하여 사용했는 지 확인했다. 다음 글에서는 Deep Dive하며, 왜 성능상의 차이가 발생하는 지를 알아보자.

profile
자바스크립트 애호가

0개의 댓글

관련 채용 정보