Skip to content

Files

Latest commit

9723008 · Oct 4, 2022

History

History
211 lines (152 loc) · 5.51 KB

20181202-map.md

File metadata and controls

211 lines (152 loc) · 5.51 KB

We will MAP you

시작하며

우리는 함수를 통해 어떤 값 또는 객체를 다른 값 또는 객체로 변환할 수 있습니다. 하나의 Input은 하나의 Ouput과 연결됩니다. 여러 개의 Input을 여러 개의 Output에 연결하고 싶을 땐 어떻게 헤야 할까요?

JavaScriptmap을 이해하도록 합시다.

두 배

여기에 아주 간단한 함수가 있습니다. 이 함수는 입력 값을 두 배로 만들어서 돌려줍니다.

function double(x) {
  return x * 2;
}

double(3) // => 6
double(13) // => 26

우리는 3을 두 배로 만들 수 있습니다. 그리고 13도 두 배로 만들 수 있습니다. double 함수를 통해 우리가 원하는 모든 숫자를 두 배로 만드는 게 가능합니다.

하지만 이 함수는 한번에 하나 밖에 다루지 못합니다. 만약 313을 배열로 만들어서 한꺼번에 처리하려면 어떻게 해야 할까요?

const xs = [3, 13];
const ys = [];

for (const x of xs) {
  ys.push(double(x));
}

ys // => [6, 26]

일단 우리가 원하는 결과는 나왔습니다. 하지만 여기엔 몇 가지 오해할 수 있는 지점이 존재합니다.

먼저, 결과 ys[]로 오해할 수 있습니다. 우리가 ys를 상수로 만들었지만 여기에 push가 가능하기 때문에 결과를 예측하기 어렵습니다. 분명히 빈 배열일 거라 생각했는데 두 개의 값이 들어갑니다.

그 다음으로, 이 작업은 “반복”이란 의미를 드러낼 필요가 없습니다. 그저 여러 개를 모두 double이란 함수로 처리한다는 의미가 드러나는 게 중요합니다.

마지막으로, 우리가 실제로 수행할 작업이 명확하게 드러나지 않습니다. 우리가 원하는 건 push가 아닙니다. double입니다. 하지만 이 코드에선 이 둘이 미묘하게 섞여있습니다.

감추기

함수를 통해 ys와 반복문, push를 감춰봅시다.

function arrayDouble(xs) {
  const ys = [];
  for (const x of xs) {
    const y = double(x);
    ys.push(y);
  }
  return ys;
}

arrayDouble([3, 13]) // => [6. 26]

사용자 입장에선 arrayDouble만 사용하면 됩니다. 위에서 논의했던 단점이 사용자에겐 노출되지 않죠.

절반

자, 이번에는 반으로 나누는 함수를 적용합시다.

function half(x) {
  return x / 2;
}

half(4) // => 2
half(12) // => 6

이것도 배열에 적용할 수 있게 해보죠.

function arrayHalf(xs) {
  const ys = [];
  for (const x of xs) {
    const y = half(x);
    ys.push(y);
  }
  return ys;
}

arrayHalf([4, 12]) // => [2, 6]

제가 이 코드를 어떻게 만들었을까요? 바로 위에 있던 코드를 복사해서 붙여 넣고 doublehalf로 바꿨습니다.

얼마나 바보 같은 짓인가요?

고차 함수

우리는 JavaScript의 함수가 “일급 함수”인 걸 알고 있습니다. 그러면 여기서 한발 더 나아가죠. 우리는 일급 함수를 인자로 받거나 반환하는 함수를 만들 수도 있습니다. 이걸 고차 함수(high-order function)라고 부릅니다.

우리는 arrayDoublearrayHalf를 고차 함수로 바꿈으로써 중복을 제거할 수 있습니다.

function arrayMap(xs, f) {
  const ys = [];
  for (const x of xs) {
    const y = f(x);
    ys.push(y);
  }
  return ys;
}

arrayMap([3, 13], double) // => [6, 26]
arrayMap([2, 12], half) // => [1, 6]

만약 익명 함수를 바로 사용하면 어떻게 될까요?

arrayMap([3, 13], x => x * 3) // => [9, 39]

참 쉽죠?

응용

좀 복잡한 데이터를 다뤄야 하는 상황을 생각해 봅니다.

const people = [
  { name: 'JOEKR', age: 13 },
  { name: 'Snoopy', age: 100 },
]

여기서 사람들(?)의 이름을 모아야 한다면 어떻게 헤야 할까요?

arrayMap(people, x => x.name)

만약 “이름 (나이)” 같은 문자열을 만들려면 어떻게 해야 할까요?

arrayMap(people, x => `${x.name} (${x.age})`)

만약 JSX라면 어떻게 될까요?

{arrayMap(people, person =>
  <div>
    <p>{person.name} ({person.age})</p>
  </div>
)}

이게 바로 React에서 여러 항목을 렌더링할 때 쓰는 방법입니다.

Array.prototype.map()

다행히 최신 JavaScript는 우리가 만든 arrayMap을 기본으로 제공하고 있습니다. 배열에 map이란 메서드로 제공하고 있죠.

[3, 13].map(double) // => [6, 26]
[3, 13].map(x => x * 3) // => [9, 39]

이게 전부입니다.

정리하며

우리는 여러 개를 처리한다는 의도가 잘 드러나는 고차 함수를 만들었습니다. 그리고 그 고차 함수를 최신 JavaScript가 기본으로 제공한다는 것도 알게 되었습니다. 이 작업은 매우 보편적인 작업입니다. 그래서 기본으로 제공하고 있죠.

다음에는 또 다른 보편적인 작업인 reduce를 알아보겠습니다.