개발자라면 누구나 코드 속 반복을 줄이고 싶어 합니다. 코드가 중복될수록 유지보수는 어려워지고, 프로그램 실행 속도도 느려지기 때문입니다. 그래서 자바스크립트에는 데이터 집합을 효율적으로 순회할 수 있는 다양한 메서드가 마련되어 있습니다.
그중 대표적인 것이 바로 map() 메서드입니다. 이 메서드는 기존 배열을 순회하면서 배열의 모든 요소에 특정 함수를 일괄 적용합니다.
이 글에서는 자바스크립트 map() 함수의 사용법을 단계별로 살펴보고, 실무에서 자주 쓰이는 세 가지 예제를 통해 개념을 확실히 익혀보겠습니다.
map() 함수란 무엇인가?
자바스크립트의 map() 메서드는 배열의 각 요소에 대해 지정된 함수를 호출하고, 그 결과값들을 모아 새로운 배열로 반환합니다. 원본 배열은 그대로 유지된다는 점이 중요한 특징입니다.
예를 들어, 배열의 모든 요소에 2를 곱하고 싶다고 가정해 봅시다. 각 요소에 2를 곱하는 함수를 만든 뒤, 이 함수를 map() 메서드에 전달하면 됩니다.
map() 함수의 기본 문법은 다음과 같습니다.
const newArray = oldArray.map(function, thisValue);
- function: 배열의 각 요소마다 실행될 콜백 함수입니다.
- thisValue: 콜백 함수 내부에서
this로 참조될 값입니다. 생략하면undefined가 기본값으로 설정됩니다.
즉, map 메서드는 콜백 함수의 실행 결과를 기반으로 새로운 배열을 생성합니다.
map() 메서드의 활용 범위는 매우 넓습니다. 가장 흔한 용도는 배열 요소 목록에 함수를 일괄 적용하는 것입니다. 예컨대 숫자 목록의 모든 값을 곱하거나, 문자열 목록에서 각 문자열의 길이를 구하는 작업 등이 여기에 해당합니다.
또한 React나 Vue.js 같은 자바스크립트 라이브러리에서 리스트를 화면에 렌더링할 때도 이 함수가 널리 사용됩니다.
map()으로 함수 호출하기
map() 메서드를 사용하면 목록의 모든 항목에 동일한 작업을 반복 수행할 수 있어, 다양한 상황에서 유용하게 활용됩니다.
쿠키 가게를 운영한다고 상상해 보세요. 모든 쿠키 가격을 5% 인상해야 하는데, 일일이 계산하지 않고 map() 메서드 한 번으로 처리할 수 있습니다.
다음은 그 코드입니다.
const cookiePrices = [1.50, 1.75, 1.60, 2.00, 2.05, 1.45];
const newCookiePrices = cookiePrices.map(cookie => {
var price = cookie * 1.05;
return price.toFixed(2);
});
console.log(newCookiePrices);
실행 결과는 다음과 같습니다.
["1.58", "1.84", "1.68", "2.10", "2.15", "1.52"]
이 예제에서는 모든 쿠키의 가격을 5% 인상했습니다. 먼저 쿠키 가격 목록을 “cookiePrices” 변수에 담았습니다. 그다음 map() 메서드와 함께 각 쿠키의 가격을 5% 올리는 함수를 전달했습니다.
“cookie * 1.05” 연산으로 인상된 가격을 계산하고, toFixed(2)로 소수점 둘째 자리까지 반올림하여 반환했습니다. 마지막으로 console.log() 메서드로 새 배열을 콘솔에 출력했습니다.
코드의 가독성을 높이고 싶다면, 계산 로직을 별도의 함수로 분리할 수도 있습니다.
function calculateIncrease(cookie) {
var price = cookie * 1.05;
return price.toFixed(2);
}
const cookiePrices = [1.50, 1.75, 1.60, 2.00, 2.05, 1.45];
const newCookiePrices = cookiePrices.map(calculateIncrease);
console.log(newCookiePrices);
결과는 앞선 예제와 동일하지만, 함수가 분리되어 코드를 읽고 관리하기가 훨씬 수월해집니다.
["1.58", "1.84", "1.68", "2.10", "2.15", "1.52"]
배열 항목 변경하기
map() 메서드는 배열의 항목 자체를 변형할 때도 자주 사용됩니다. 쿠키 가게에서 고객 충성도 프로그램을 운영한다고 가정해 봅시다. 쿠키를 구매할 때마다 10포인트가 적립되고, 100포인트를 모으면 무료 쿠키 한 개를 받을 수 있습니다.
다음 프로그램은 고객별 포인트를 계산하는 작업을 처리합니다.
var customers = [
{ name: "Hannah Geoffrey", cookiesPurchased: 2 },
{ name: "Peter Clarkson", cookiesPurchased: 3 },
{ name: "Steven Hanson", cookiesPurchased: 7 }
]
function calculateLoyaltyPoints(customer) {
var newCustomer = {
name: customer.name,
cookiesPurchased: customer.cookiesPurchased,
points: customer.cookiesPurchased * 10
}
return newCustomer;
}
var customersWithPoints = customers.map(calculateLoyaltyPoints);
console.log(customersWithPoints);
실행 결과는 다음과 같습니다.
[{ cookiesPurchased: 2, name: "Hannah Geoffrey", points: 20 }, { cookiesPurchased: 3, name: "Peter Clarkson", points: 30 }, { cookiesPurchased: 7, name: "Steven Hanson", points: 70 }]
이 예제에서는 각 고객이 구매한 쿠키 수를 기준으로 지급해야 할 포인트를 계산했습니다.
먼저 “customers”라는 객체 배열을 선언했습니다. 이 배열에는 key:value 쌍 형태로 고객의 이름과 구매한 쿠키 수가 저장되어 있습니다.
그다음 calculateLoyaltyPoints() 함수를 선언했습니다. 이 함수는 각 고객 정보에 “points”라는 새 속성을 추가하며, 그 값은 구매한 쿠키 수에 10을 곱해 산출됩니다.
이후 map() 메서드로 고객 목록을 순회하며 calculateLoyaltyPoints() 함수를 적용하고, 최종적으로 포인트가 추가된 수정된 고객 목록을 출력했습니다.
라이브러리에서 리스트 렌더링하기
map() 메서드는 React 같은 자바스크립트 라이브러리에서도 널리 쓰입니다. 주된 목적은 목록의 항목들을 화면에 렌더링하는 것입니다. React에서 map()을 활용하는 예제를 살펴보겠습니다.
가게에서 판매하는 쿠키 목록을 웹사이트에 표시하고 싶다고 가정해 봅시다. 다음 코드로 구현할 수 있습니다.
import React from "react";
import ReactDOM from "react-dom";
var cookies = ["Raspberry Chocolate Chip", "White Chocolate Chip", "Oat", "Milk Chocolate Chip"];
const CookieList = () => (
<div>
<ul>{cookies.map((cookie, i) =>
<li key={i}>{cookie}</li>
)}
</ul>
</div>
);
const root = document.getElementById("root");
ReactDOM.render(<CookieList />, root);
이 코드는 React에서 리스트를 렌더링하는 컴포넌트를 생성합니다. 각 리스트 항목은 <li> 태그로 감싸지며, map()을 통해 렌더링됩니다. map()은 목록의 각 항목마다 개별 <li> 태그를 만들어 주고, 변수 “i”는 각 항목에 고유한 key를 부여합니다.
map() vs. 다른 반복자 메서드
map은 자바스크립트의 반복자(iterator) 메서드 중 하나입니다. 반복자 메서드를 사용하면 목록의 모든 항목을 순회하면서 특정 작업을 수행할 수 있습니다.
map() 함수를 사용하기로 결정하기 전에, 다른 반복자 메서드가 더 적합하지는 않은지 먼저 고민해 보는 것이 좋은 습관입니다. 그래야 작업에 맞는 올바른 도구를 선택할 수 있습니다.
자바스크립트에는 다음과 같은 반복자 메서드들이 있습니다.
- reduce(): 배열을 하나의 값으로 축약합니다. 배열의 모든 항목을 더하는 등의 작업에 가장 적합합니다.
- filter(): 특정 조건을 충족하지 않는 항목을 목록에서 제거합니다.
- forEach(): 목록의 모든 항목에 함수를 실행합니다. for 루프처럼 배열을 순회하며 각 항목에 작업을 수행할 수 있습니다.
“map이 forEach() 메서드와 꽤 비슷해 보이는데, 둘이 같은 건 아닐까?”라고 생각하셨다면 좋은 질문입니다. 두 메서드 사이에는 미묘하지만 중요한 차이가 있습니다.
map() 함수는 목록을 순회하면서 각 항목을 변경하고, 그 결과로 새로운 배열을 반환합니다. 반면 forEach() 함수는 목록을 순회하면서 부수 효과(side effect)로 어떤 작업을 수행할 뿐, 새 배열을 반환하지 않습니다.
따라서 목록의 모든 항목에 함수를 적용해야 하거나, React 같은 프레임워크에서 리스트 컴포넌트를 선언하거나, 목록의 내용을 변형해야 할 때는 map() 함수를 사용하는 것이 가장 적합합니다.
마무리
map() 메서드는 반복적인 작업을 여러 번 수행해야 할 때 매우 유용하며, React에서 리스트 같은 컴포넌트를 선언할 때도 필수적인 도구입니다.
이 튜토리얼에서는 map() 메서드의 세 가지 대표적인 활용 사례를 살펴봤습니다. 이제 여러분도 전문 개발자처럼 자바스크립트 map() 메서드를 자신 있게 활용할 준비가 되었습니다!