ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • JS - Map
    개발 2022. 4. 13. 21:00

     

    학습목표

    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

     

     

    댓글

onul-hoi front-end developer limchansoo