본문 바로가기
Script/JavaScript

[JavaScript] Chapter 29. Array map

by song.ift 2023. 1. 10.

값을 여러개 가지고 있는 배열에서 모든 값을 꺼내고자 할 때,

꺼내는 방법은 정말 다양하게 알려져 있다.

이러한 배열에서 값 꺼내는 방법 중 map( ) 을 다뤄보도록 하자.

 

map 정의

Array.prototype.map ( callbackfn [ , thisArg ] )

주로 주어진 배열의 값을 재정의 할 때, 사용하는 방법으로 

ECMA에는 "주어진 배열의 값들을 오름차순으로 접근해 callbackfn을 통해 새로운 값을 정의하고 신규 배열을 만들어 반환한다"라고 정의되어있다.

const numbers = [1, 2, 3, 4, 5];
const result = numbers.map(number => number * number);

console.log(numbers);
// [1, 2, 3, 4, 5];

console.log(result);
// [1, 4, 9, 16, 25]

 

아래와 같은 배열 arr 이 있다고 가정해 보자.

let arr = [ 10, 20, 30, 40, 50 ];

 

arr 배열의 5 개의 값을 전부 꺼내 콘솔에 찍어보고 싶다면 아래처럼 for 문을 이용한 사례도 많을 것이다.

const arr = [ 10, 20, 30, 40, 50 ];

// 기본 for문 방식
for (let index = 0; index < arr.length; index++) {
  console.log(arr[index]);
}

// 향상된 for문 방식
for (let item of arr) {
  console.log(item);
}

향상된 for문에 대한 설명은 길게는 안하고 arr 배열의 값을 item 에 하나씩 담아오는 개념이라는거만 알고 보자.

여튼 이러한 for문의 형태가 아닌, map( ) 함수를 사용해 바꿔보도록 할건데,

map( ) 함수는 값과 인덱스를 인자로 받아 자동으로 for문을 돌려 값을 빼도록 해준다.

쉽게 말해 map( ) 함수의 값 인자는 향상된 for문의 item 인자와 같은 역할,

 

map( ) 함수의 인덱스 인자는 기본 for문 방식의 index 와 같은 역할이라 보면 된다.

 

위 예제의 코드를 map( ) 을 적용시켜 바꾼 예제 코드는 다음과 같다.

const arr = [ 10, 20, 30, 40, 50 ];

// 일반 함수 형태
arr.map(function(item, index) {
  console.log(index + "번 값", item);
});

// 화살표 함수 형태
arr.map((item, index) => {
  console.log(index + "번 값", item);
});

index 인자는 배열안의 인덱스(몇 번째)를 의미하며 item 에는 배열안의 값들이 하나씩 순서대로 담긴다.

보통 인덱스를 이용해 어떤 작업을 할 땐 기본 for문을, 인덱스를 사용하지 않을 땐 향상된 for문을 사용한다 하면,

이러한 두 가지의 경우를 합친 상황 때 능동적으로 사용하기위해 보통 map( ) 함수를 사용하곤 한다.

 

위 예제의 실행 화면은 다음과 같다.

 

 

map은 forEach와 마찬가지로 Array의 각 요소를 순회하며 callback 함수를 실행한다.

다만, callback에서 return 되는 값을 배열로 만들어낸다.

[].map(callback, thisArg)

const arr = [0,1,2,3];

let squaredArr = arr.map(function(element){
  return element * element;
});
// 혹은 arrow 함수 가능
squaredArr = arr.map(element => element * element);

console.log(squaredArr);  // [ 0, 1, 4, 9 ]

위 코드를 보면 배열 속 숫자들이 제곱되어 새로운 배열이 생성되는 모습을 볼 수 있다. 

 

callback 함수 인자

map의 callback 함수에는 forEach와 마찬가지로 index와 전체 배열을 인자로 사용할 수 있다.

const arr = [0,1,2,3];

let squaredArr = arr.map(function(element, index, array){
  console.log(`${array}의 ${index}번째 인자 : ${element}`);
  return element * element;
});
/*
0,1,2,3의 0번째 인자 : 0
0,1,2,3의 1번째 인자 : 1
0,1,2,3의 2번째 인자 : 2
0,1,2,3의 3번째 인자 : 3
*/

console.log(squaredArr);  // [ 0, 1, 4, 9 ]

 

유의할 점

for문은 continue나 break로 반복을 제어할 수 있지만, map은 forEach와 마찬가지로 throw(예외)를 발생시키지 않으면 중간에 반복을 종료할 수 없다.

 

 

다양한 활용법

  • 고차 함수 사용하기
const numbers = [1, 2, 3, 4, 5];

// 제곱근 구하기
const squares = numbers.map(Math.sqrt);

console.log(squares);
// [1, 1.4142135623730951, 1.7320508075688772, 2, 2.23606797749979]

// 곱 구하기
const double = value => value * 2;
const doubles = numbers.map(double);

console.log(doubles);
// [2, 4, 6, 8, 10]

map은 고차 함수를 사용해 미리 정해둔 식이나 정의되어 있는 식을 이용할 수 있어 편리하다.

 

  • 새로운 형태의 값 생성하기
const users = [
    { name: 'YD', age: 22 },
    { name: 'Bill', age: 32 },
    { name: 'Andy', age: 21 },
    { name: 'Roky', age: 35 },
];

const ages = users.map(user => user.age);

console.log(ages);
// [22, 32, 21, 35]

배열에 들어가 있는 값 중 특정 값만 추출해 새로운 형태의 배열을 만들어 낼 수 있다.

 

  • 특정 요소만 재정의하기
const users = [
    { name: 'YD', age: 22 },
    { name: 'Bill', age: 32 },
    { name: 'Andy', age: 21 },
    { name: 'Roky', age: 35 },
];

const newUsers = users.map(user => {
    if (user.name === 'YD') {
        return { ...user, age: 18 };
    }

    return { ...user };
});

console.log(newUsers);
// [{name: "YD", age: 18}, {name: "Bill", age: 32}, {name: "Andy", age: 21}, {name: "Roky", age: 35}]

배열 요소 중 특정 조건을 만족하는 대상만 값을 재정의해서 사용할 수 있다.

 

  • 문자를 배열로 바꾸기
const message = 'Hello world';

const newMessage = Array.prototype.map.call(message, char => `${char}`);

console.log(newMessage);
// ["H", "e", "l", "l", "o", " ", "w", "o", "r", "l", "d"]

call을 이용하면 다른 객체의 context를 사용해 문자를 배열로 반환하는 데에 사용할 수 있다.

 

  • React에 적용해보기
function Contacts() {
    const contactData = [
        { name: "YD", phone: "010-0000-0001" },
        { name: "Bill", phone: "010-0000-0002" },
        { name: "Andy", phone: "010-0000-0003" },
        { name: "Roky", phone: "010-0000-0004" }
    ];

    return (
        <div>
            <h1>Contacts</h1>
            <ul>
                {contactData.map((contact, index) => {
                    return (<li key={index} name={contact.name} phone={contact.phone} />);
                })}
            </ul>
        </div>
    );
}

React에서 화면을 구성할 때에도 map을 활용하면 보다 쉽게 화면 요소를 정의할 수 있다.

 

약간의 실용적인 예

<body onload="render()">
  <table>
    <thead>
      <th>이름</th>
      <th>전화번호</th>
    </thead>
    
    <tbody id="test">
    </tbody>
  </table>
  
  <script>
    const userList = reqUserList(); // 함수 선언 전 변수 선언은 호이스팅에 의해 허락됨

    function reqUserList(){
      // ajax를 통해 데이터를 불러왔다고 가정
      return [
        { name: "윾또막", phone: "010-1111-1111" },
        { name: "장꾸", phone: "010-2222-2222" },
      ];
    }

    function makeListToDom(list){
      const dom = list.map(elem => `<tr><td>${elem.name}</td><td>${elem.phone}</td></tr>`);

      return dom;
    }

    function renderList(dom){
      const d = dom.join('');

      document.getElementById("test").innerHTML = d;
    }

    function render(){
      const userListDom = makeListToDom(userList);

      renderList(userListDom);
    }
  </script>
</body>

위 코드는 유저 목록 api를 요청한다고 가정하여, 받아온 데이터를 table에 그리는 작업을 한다.

map 함수를 사용하여 html 형태의 배열을 생성하고, 이를 innerHTML을 사용하여 tbody에 삽입한다.

서버로부터 배열 형태의 데이터를 요청하고, 화면에 그려야 하는 경우에 효과적으로 사용할 수 있다.

댓글