-
학습목표
ES6 이후 등장한 Map 객체가 Object와 어떤 차이가 있는지 인지하고 기본 사용법을 익혀보자.
Object
자바스크립트에서 객체를 선언하고, 접근할때는 다음과 같은 방법으로 사용한다.
선언
let userObj = new Object() let userObj = {}
대체로 생성자로 선언하는 방식보다 리터럴 방식으로 많이 사용된다.
선언된 객체에 값을 정의하는 방식은 아래와 같다.
속성과 값 정의
userObj.name = 'LIMCHANSOO'; userObj.email = 'cslim0527@gmail.com'; userObj.phone = '01012341234'
선언과 속성과 값을 동시에 정의하기 위해서는 보통 리터럴 방식으로 객체 안의 key-value 쌍으로 값을 정의 할 수 있다.
let userObj = { name: 'LIMCHANSOO', email: 'cslim0527@gmail.com', phone: '01012345678', }
값 접근하기
console.log('기존의 Object 객체: ', userObj) console.log('Object 객체 속성 접근: ', userObj.name)
계산된 값을 Key로 사용한다면..
실제로 개발을 하다보면 정해진 key값을 사용해서만 객체 속성을 정의하지 않고 변수를 사용하여 동적인 key값을 정의할때가 있다.
이럴 땐 대괄호를 사용하여 계산된 값을 key값으로 사용 할 수 있다.
const color = prompt('색깔을 입력하세요'); const obj = { [color + '_bag_quantity']: 5 } console.log(obj)
숫자를 Key로 사용한다면..
const fruit = { 1: 'apple', 2: 'banana', 3: 'carrot' } console.log(fruit.1) //Uncaught SyntaxError: Unexpected number
과일의 종류를 Number값을 key로 갖는 객체를 선언한 후 'apple' 값을 출력하는 코드에서 위와 같은 에러를 볼 수 있는데, 이런 경우 객체에서도 객체에 접근하기 위해서는 대괄호를 사용한다.
const fruit = { 1: 'apple', 2: 'banana', 3: 'carrot' } console.log(fruit[1]) // 'apple'
특이한 점은 Number값을 key로 갖고 있지만 문자열 '1' 로 접근해도 같은 값을 출력 할 수 있다.
const fruit = { 1: 'apple', 2: 'banana', 3: 'carrot' } console.log(fruit['1']) // 'apple'
이는 Number를 String으로 인식하는 애매모호한 상황을 초래할 수 있어서 명확한 접근법이라고 보기 힘들다.
Iterable하지 않다.
Symbol.iterator가 존재하지 않는 Object는 iterable하지 않아 순회 할 수 없다.
길이를 알 수 없다.
정확히는 길이를 알 수 없는 것보다는 "바로 뽑아서" 알아낼 수 없다.
길이는 알아내기 위해서는 별도의 방법으로 key의 갯수를 알아내는 방법이 있다.
const fruit = { 1: 'apple', 2: 'banana', 3: 'carrot' } const fruitLength = Object.keys(fruit).length console.log(fruitLength)
Map
Map은 key가 있는 데이터를 저장한다는 점에서 객체와 유사하지만, 키 값으로 모든 자료형을 허용한다는 점에서 차이가 있다.
선언 : new Map()
let userMap = new Map();
맵 객체 생성자를 통해 만들수 있다.
속성과 값 정의 : map.set(key, value)
Map 속성을 정의하기 위한 방법으로 사용되며, 이 메서드는 Map 자신이 리턴되어 체이닝이 가능하다.
userMap.set('name', 'LIMCHANSOO') userMap.set('email', 'cslim0527@gmail.com') userMap.set('phone', '01012341234') userMap.set('name', 'LIMCHANSOO').set('email', 'cslim0527@gmail.com').set('phone', '01012341234')
set 메서드를 통해서 첫번째 인자를 key로 사용하며, 두번째 인자는 value로 저장 된다.
Map 객체를 출력한 모습 선언과 속성과 값을 동시에 정의하기 위해서는 아래와 같이 사용해야 한다.
map.set([[key, value], [key, value]])
let userMap = new Map( [ ['name', 'LIMCHANSOO'], ['email', 'cslim0527@gmail.com'], ['phone', '01012341234'] ] );
여기서 잠깐!
Object와 Map의 차이위에서 Map 객체를 선언 할 때 key 값을 String 값으로 명시적으로 따옴표를 붙여 넣어주었다.
그럼 key값을 정의할때 String으로 정의했으니 당연히도 String으로 접근 할 수 있을 것이다.
하지만 일반 객체에서 key값을 정의 할때를 보자.
따옴표를 붙이지 않았다.
객체의 값에 접근 할 때 대괄호를 사용해 접근하는 방법이 있다고 했는데
그럼 아래의 userObj의 name값을 가져오려면 userObj[name] 으로 접근해도 가능 한것이 아닐까?
선언한 userObj name값에 접근하기 결과는 예상과 다르게 undefined로 출력된다.
위 경우에는 key값으로 쓰인 name이 변수로 취급되었기 때문에 userObj[undefined]를 접근한것과 마찬가지이다.
이 처럼 다소 헷갈릴수 있는 일반 객체 방식보다 Map 객체는 보다 명확한 방법으로 값에 접근 할 수 있다.
값 접근하기 : map.get(key)
Map 속성 값에 접근하기 위한 방법으로 사용되며, 해당 value를 리턴한다.
userMap.get('name')
Map 객체에서 제공하는 메서드인 get 함수는 key값을 인자로 넘겨 해당 value에 접근 할 수 있다.
일반 객체와 비교해 보다 명확하게 get() 함수 를 통해서 String으로 정의했던 'name' 과 똑같은 key를 사용해 접근하니
헷갈릴 이유가 없다.
다른 자료형을 key값으로 쓴다면..
일반 객체에서 문자열이 아닌 다른 자료형을 key값으로 사용하려면 대괄호를 사용해서 정의했었다.
하지만 Map 객체에서는 단지 set() 을 통해서 모든 자료형에 대해서 속성을 만들 수 있다.
map.set('1', 'str1'); // 문자형 키 map.set(1, 'num1'); // 숫자형 키 map.set(true, 'bool1'); // 불린형 키 map.set(getString(), 'str1'); // 함수 키 map.set(Symbol("foo"), 'num1'); // 심볼 키 map.set({name: 'LCS'}, 'num1'); // 심지어 객체도 키값이 된다.
Iterable한 객체이다.
Map의 프로토타입에는 Symbol.iterator가 존재하기 때문에 순회 할 수 있는 대상이 된다.
반복을 사용하기 위해서는 다음과 같은 메서드들이 반환하는 이터러블 객체를 사용 할 수 있다.
- map.keys() – 각 요소의 키를 모은 반복 가능한(iterable, 이터러블) 객체를 반환
- map.values() – 각 요소의 값을 모은 이터러블 객체를 반환
- map.entries() – 요소의 [키, 값]을 한 쌍으로 하는 이터러블 객체를 반환
이터러블 하다는 것은 Spread 연산자를 사용 할 수 있다는 것이기 때문에 쉽게 Array로 변환도 가능하다.
길이를 알 수 있다.
Map 객체는 size 속성을 갖고 있다.
이것은 Array의 length와 같이 해당 객체의 요소 갯수 정보를 담고 있기 때문에 Object에서 length값을 얻기위해 해야하는 번거로운 작업과 비교가 되는 부분이다.
userMap.size // 3
Map의 size 속성
그 외에도..
객체와 Map의 변환을 위해 사용 할 수 있는 다양한 함수를 통해 데이터 변환이 필요한 작업에서 사용한다면
코드의 질을 높이고 가독성 있게 코드를 작성 할 수 있는 내용이다.
- 배열과 유사하게 객체를 순회할 수 있는 forEach 메서드
// 각 (키, 값) 쌍을 대상으로 함수를 실행 recipeMap.forEach( (value, key, map) => { alert(`${key}: ${value}`); // cucumber: 500 ... });
- 객체를 Map으로 바꿔주는 Object.entries
let obj = { name: "John", age: 30 }; let map = new Map(Object.entries(obj)); alert( map.get('name') ); // John
- Map을 객체로 바꿔주는 Object.fromEntries
let map = new Map(); map.set('banana', 1); map.set('orange', 2); map.set('meat', 4); let obj = Object.fromEntries(map.entries()); // 맵을 일반 객체로 변환 (*) // 맵이 객체가 되었습니다! // obj = { banana: 1, orange: 2, meat: 4 } alert(obj.orange); // 2
'개발' 카테고리의 다른 글
TIL - Next.js Google Analytics 코드 적용하기 (1) 2022.04.26 TIL - Mac 업로드 파일 한글 깨짐 (자모분리현상) (0) 2022.04.19 React - react hook form (0) 2022.03.31 TIL - CSS Module (0) 2022.03.28 TIL - Next.js 연습 프로젝트 #2 (0) 2022.03.20