함수형 프로그래밍과 JavaScript ES6+ 6. 장바구니 예시

|

inflearn의 함수형 프로그래밍과 JavaScript ES6+를 보고 공부한 것을 정리합니다.

총 수량

const products = [
    { name: '반팔티', price: 15000, quantity: 1 },
    { name: '긴팔티', price: 20000, quantity: 2 },
    { name: '핸드폰케이스', price: 15000, quantity: 3 },
    { name: '후드티', price: 30000, quantity: 4 },
    { name: '바지', price: 25000, quantity: 5 },
];
const add = (a, b) => a + b;

const total_quantity =  pipe(
    map(p => p.quantity),
    reduce(add));

log(total_quantity(products)); // 15

총 가격

const total_price = pipe(
    map(p => p.quantity * p.price),
    reduce(add));

log(total_price(products)); // 345000

추상화 레벨 높이기

위의 두 함수는 products라는 도메인에 대해서만 사용 가능하다. 다른 도메인에 대해서도 범용적으로 사용 가능하도록 다음과 같은 함수를 만들 수 있다.

const sum = curry((f, iter) => go(
    iter,
    map(f),
    reduce(add)
));

위의 함수는 함수와 이터러블을 입력받아서, 해당 이터러블에 대해 함수에 맞게 추출 (map) 하고 그것에 대한 합산을 계산하는 것이다. 이를 토대로 위의 함수들은 다음과 같이 바뀔 수 있다.

const total_quantity2 = sum(p => p.quantity);
const total_price2 = sum(p => p.quantity * p.price);

log(total_quantity2(products));
log(total_price2(products));

다른 도메인에 대해서도 사용 가능하다.

log(sum(u => u.age, [
    {age: 30},
    {age: 20},
    {age: 10}
])); // 60

sum은 이제 도메인에 구애받지 않으므로, 추상화 레벨이 훨씬 높다고 할 수 있다!

HTML로 출력하기

초기 템플릿

document.querySelector('#cart').innerHTML= '
    <table>
      <tr>
        <th>상품 이름</th>
        <th>가격</th>
        <th>수량</th>
        <th>총 가격</th>
      </tr>
      <tr>
        <td>반팔티</td>
        <td>10000</td>
        <td><input type="number" value="3"></td>
        <td>30000</td>
      </tr>
      <tr>
        <td>반팔티</td>
        <td>10000</td>
        <td><input type="number" value="3"></td>
        <td>30000</td>
      </tr>
';

총 수량, 총 가격 추가

document.querySelector('#cart').innerHTML= '
    <table>
      <tr>
        <th>상품 이름</th>
        <th>가격</th>
        <th>수량</th>
        <th>총 가격</th>
      </tr>
      <tr>
        <td>반팔티</td>
        <td>10000</td>
        <td><input type="number" value="3"></td>
        <td>30000</td>
      </tr>
      <tr>
        <td>반팔티</td>
        <td>10000</td>
        <td><input type="number" value="3"></td>
        <td>30000</td>
      </tr>
      <tr>
        <td colspan="2">합계</td>
        <td>${total_quantity(products)}</td>
        <td>${total_price(products)}</td>
      </tr>
';
views
초기 템플릿

### 상품들의 목록을 출력하도록

 document.querySelector('#cart').innerHTML= '
     <table>
       <tr>
         <th>상품 이름</th>
         <th>가격</th>
         <th>수량</th>
         <th>총 가격</th>
       </tr>
       <tr>
       ${go(products,
              map(p => `
                  <tr>
                    <td>${p.name}</td>
                    <td>${p.price}</td>
                    <td><input type="number" value="${p.quantity}"</td>
                  </tr>
              `)
          )}
       </tr>
       <tr>
         <td colspan="2">합계</td>
         <td>${total_quantity(products)}</td>
         <td>${total_price(products)}</td>
       </tr>
 ';
views

원하는 대로 출력은 됐는데, 앞에 `````가 생겼다. 그 이유는 이것이 배열의 형태로 출력이 되었기 때문이다. log를 찍어서 확인해보면 다음과 같다.

views
배열의 형태

그래서, 다음과 같이 add 코드를 추가하여 이 배열을 문자열로 만들어준다.

document.querySelector('#cart').innerHTML= '
    <table>
      <tr>
        <th>상품 이름</th>
        <th>가격</th>
        <th>수량</th>
        <th>총 가격</th>
      </tr>
      <tr>
      ${go(products,
             map(p => `
                 <tr>
                   <td>${p.name}</td>
                   <td>${p.price}</td>
                   <td><input type="number" value="${p.quantity}"</td>
                 </tr>
             `),
             reduce(add))}
      </tr>
      <tr>
        <td colspan="2">합계</td>
        <td>${total_quantity(products)}</td>
        <td>${total_price(products)}</td>
      </tr>
';

그런데 위의 형태는 이전에 만들었던 sum과 같다. 그러므로 다음과 같이 바꿀 수 있다.

document.querySelector('#cart').innerHTML= '
    <table>
      <tr>
        <th>상품 이름</th>
        <th>가격</th>
        <th>수량</th>
        <th>총 가격</th>
      </tr>
      <tr>
      ${go(products,
             sum(p => `
                 <tr>
                   <td>${p.name}</td>
                   <td>${p.price}</td>
                   <td><input type="number" value="${p.quantity}"</td>
                 </tr>
             `))}
      </tr>
      <tr>
        <td colspan="2">합계</td>
        <td>${total_quantity(products)}</td>
        <td>${total_price(products)}</td>
      </tr>
';
views
로그로 찍은 것

선택된 상품들만 출력되도록

이는 장바구니이므로, 다음과 같이 선택할 수 있도록 한다. 우선 products에 is_selected 옵션을 추가한다.

const products = [
    { name: '반팔티', price: 15000, quantity: 1, is_selected: true },
    { name: '긴팔티', price: 20000, quantity: 2, is_selected: false },
    { name: '핸드폰케이스', price: 15000, quantity: 3, is_selected: true },
    { name: '후드티', price: 30000, quantity: 4, is_selected: false },
    { name: '바지', price: 25000, quantity: 5, is_selected: false },
];
document.querySelector('#cart').innerHTML= '
    <table>
      <tr>
        <th></th>
        <th>상품 이름</th>
        <th>가격</th>
        <th>수량</th>
        <th>총 가격</th>
      </tr>
      <tr>
      ${go(products,
             sum(p => `
                 <tr>
                   <td><input type="checkbox" ${p.is_selected ? 'checked' : ''}></td>
                   <td>${p.name}</td>
                   <td>${p.price}</td>
                   <td><input type="number" value="${p.quantity}"</td>
                 </tr>
             `))}
      </tr>
      <tr>
        <td colspan="2">합계</td>
        <td>${total_quantity(filter(p => p.is_selected, products))}</td>
        <td>${total_price(filter(p => p.is_selected, products))}</td>
      </tr>
';
views
최종 모습

함수형 프로그래밍과 JavaScript ES6+ 5. 코드를 값으로 다루어 표현력 높이기

|

inflearn의 함수형 프로그래밍과 JavaScript ES6+를 보고 공부한 것을 정리합니다.

go

  • 함수형 프로그래밍에서는 코드를 값으로 다루는 아이디어를 많이 사용한다.
  • 이렇게 하면 어떤 함수가 코드인 함수를 받아서 평가하는 시점을 원하는 대로 지정할 수 있기 때문에, 코드의 표현력을 높이는 등의 다양하고 좋은 아이디어를 많이 가지고 있다.
const add = (a, b) => a+b;

log(
    reduce(
        add,
        map(p => p.price,
        filter(p => p.price < 20000, products))
    )
);
  • 위의 코드는 함수가 중첩되어 있다 보니 읽기에 불편하다.
const go = (...args) => reduce((a, f) => f(a), args);

go(
    0,
    a => a + 1,
    a => a + 10,
    a => a + 100,
    log);
  • go라는 함수를 생성한다.
  • 우리가 이 함수에 대하여 기대하는 것은 초기값 0을 시작으로 해서 연속적으로 실행되며, 원하는 값이 마지막으로 111로 찍히는 것과 같은 동작이다.
  • 즉, 인자들을 받아서 하나의 값으로 축약해나가는 것이다.
  • 인자들이 들어왔다고 했을 때 첫 번째 인자를 다음 함수에, 다음 함수의 결과를 다시 그 다음 함수에게 전달하는 식으로 계속해서 연속적으로 하나의 일을 수행해야 한다.
  • 축약하는 로직은 reduce!
  • 그러므로 go 함수를 다음과 같이 작성할 수 있다.
const go = (...args) => reduce((a, f) => f(a), args);
  • args를 특정 함수로 축약해서 하나의 값으로 만들어가는 것이다.
  • reduce를 사용하면 특정 리스트를 축약해나가는 코드를 작성할 때 쉽고 재밌게 만들 수 있다.

pipe

  • go 함수와 다르게 함수를 리턴하는 함수
  • go 함수는 즉시 함수들과 인자를 전달하여 어떤 값을 평가하는 데에 사용된다면
  • pipe 함수는 함수들이 나열되어 있는 합성된 함수를 만드는 함수이다.
const f = pipe(
  a => a + 1,
  a => a + 10,
  a => a + 100
);
  • 이런 식으로 새로운 함수를 리턴할 것을 예상하면서 pipe 함수를 작성해 보자.
const pipe = (...fs) => (a) => go(a, ...fs);
  • 함수를 리턴해주고
  • 함수들인 fs를 인자로 받아준다.
  • 인자는 나중에 받을 것이므로 리턴하는 함수의 인자 a로 넣고,
  • go(a, ...fs)를 실행하는 함수를 리턴해주면 된다!
  • 하지만 이렇게 pipe 함수를 만들게 되면 인자가 하나인 경우밖에 처리할 수 없다.
  • 예를 들어,
const f = pipe(
    (a, b) => a + b,
    a => a + 1,
    a => a + 10,
    a => a + 100
);

log(f(0, 1));
  • 이런 식으로 사용할 수 없다.
  • 이렇게 동작하도록 하고 싶다면
const f = pipe(
    a => a + 1,
    a => a + 10,
    a => a + 100
);

log(f(add(0, 1)));
  • 함수를 호출할 때 add() 함수를 사용해야 한다.
  • 첫 번째 함수에 한하여 여러 개의 인자도 받도록 pipe 함수를 변경하면 다음과 같다.
const pipe = (f, ...fs) => (...as) => go(f(...as), ...fs);
  • f : 첫 번째 함수
  • ...as : 여러 개의 인자를 받아서
  • f(...as) : go 함수의 첫 번째 인자에 하나의 값으로 평가되도록 하는 함수를 넣어 준다.

go를 사용하여 읽기 좋은 코드로 만들기

go(
    products, // products 로 시작해
    products => filter(p => p.price < 20000, products), // 1. filter
    products => map(p => p.price, products), // 2. map
    prices => reduce(add, prices), // 3. reduce
    log // 4. log
);
  • 코드는 좀 더 복잡해졌지만
  • 좀 더 읽기에 편해짐!

go+curry를 사용하여 더 읽기 좋은 코드로 만들기

  • curry : 역시 코드를 값으로 다루면서, 받아둔 함수를 내가 원하는 시점에 평가시키는 함수
    1. 함수를 받아서 함수를 리턴
    2. 인자를 받아서 원하는 개수만큼의 인자가 들어왔을 때 받아둔 함수를 평가시킨다.
  • 인자가 두 개 이상이라면 (length 프로퍼티가 있다면) 받아둔 함수를 실행하고 아니라면 함수를 다시 리턴한 후, 그 이후에 받은 인자들을 합쳐서 실행하는 함수
const curry = f => // 함수를 받아서
    (a, ..._) => _.length ? f(a, ..._) : (..._) => f(a, ..._); // a : 첫번째 인자, _ : 나머지 인자
const mult = (a, b) => a * b;

이 함수를 만들 때 curry로 한 번 감싸면

const mult = curry((a, b) => a * b);

위와 같이 된다. 이를 순차적으로 출력해보자.

log(mult); // (a, ..._) => _.length ? f(a, ..._) : (..._) => f(a, ..._) 함수가 리턴됨
log(mult(1)); // (..._) => f(a, ..._)
log(mult(1)(2)); // 2
log(mult(1, 2)); // 2

아래와 같은 응용도 가능하다.

const mult3 = mult(3);
log(mult3(10));
log(mult3(5));
log(mult3(1));

이를 활용해 코드를 좀 더! 간결하게 만들어본다. 우선, map, filter, reduce를 전부 curry로 감싼다.

const curry = f =>
    (a, ..._) => _.length ? f(a, ..._) : (..._) => f(a, ..._);

const map = curry((f, iter) => {
    let res = [];
    for (const a of iter) {
        res.push(f(a));
    }
    return res;
});

const filter = curry((f, iter) => {
    let res = [];
    for (const a of iter) {
        if (f(a)) res.push(a);
    }
    return res;
});

const reduce = curry((f, acc, iter) => {
    if (!iter) {
        iter = acc[Symbol.iterator]();
        acc = iter.next().value;
    }
    for (const a of iter) {
        acc = f(acc, a);
    }
    return acc;
});

이제 이 모든 함수들이 인자를 하나만 받으면 이후의 인자를 받도록 기다리는 함수가 된다!

go(
    products, // products 로 시작해
    products => filter(p => p.price < 20000)(products), // 1. filter
    products => map(p => p.price)(products), // 2. map
    prices => reduce(add)(prices), // 3. reduce
    log // 4. log
);

이렇게 쓸 수 바꿀 수 있다. 여기서 다음과 같이 생각해볼 수 있다.

a => f(a)f와 같다. 즉, 인자 하나를 받아 거기에 1을 더하는 함수 add1이 있다고 하자. 이것을 a => add1(a) 라고 하는 것과, add1이라고 하는 것의 본질적 의미는 같다!

그렇다면 위의 코드를 다음과 같이 간결하게 만들 수 있다.

go(
    products, // products 로 시작해
    filter(p => p.price < 20000), // 1. filter
    map(p => p.price), // 2. map
    reduce(add), // 3. reduce
    log // 4. log
);

함수를 부분적으로 실행하는 curry 함수를 통해 보다 간결한 표현이 가능해진다.

함수 조합으로 함수 만들기

다음의 두 코드에는 중복이 존재한다. (map, reduce)

go(
    products,
    filter(p => p.price < 20000),
    map(p => p.price),
    reduce(add),
    log
);

go(
    products,
    filter(p => p.price >= 20000),
    map(p => p.price),
    reduce(add),
    log
);

이를 새 함수를 만듦으로써 쉽게 제거할 수 있다.

const total_price = pipe(
    map(p => p.price),
    reduce(add));

go(
products,
filter(p => p.price < 20000),
total_price,
log
);

go(
products,
filter(p => p.price >= 20000),
total_price,
log
);

다음과 같은 방식으로도 가능하다.

const base_total_price = predi => pipe(
    filter(predi),
    total_price
);

go(
    products,
    base_total_price(p => p.price < 20000),
    log
);

go(
    products,
    base_total_price(p => p.price >= 20000),
    log
);

함수형 프로그래밍에서는 고차함수들을 함수의 조합으로 계속해서 잘게 나누어가면서 중복을 제거하는 식으로, 또 재사용성을 높이는 방식으로 사용할 수 있다.

200305TIL

|

오늘 한 것

  • 자바스크립트 전개 연산자 찾아보고 정리
  • 자바스크립트 함수형 프로그래밍 5강 수강 및 정리
  • 자바스크립트 함수형 프로그래밍 6강 수강 및 정리
  • 지원서 작성 및 제출

함수형 프로그래밍과 JavaScript ES6+ 4. map, filter, reduce

|

inflearn의 함수형 프로그래밍과 JavaScript ES6+를 보고 공부한 것을 정리합니다.

map

const products = [
    { name: '반팔티', price: 15000 }, // 각각 상품 하나
    { name: '긴팔티', price: 20000 },
    { name: '핸드폰케이스', price: 15000 },
    { name: '후드티', price: 30000 },
    { name: '바지', price: 25000 },
];
  • 보통 이러한 데이터를 다룰 때 products에 있는 상품의 이름들을 따로 모아서 출력하거나, 가격들을 따로 배열에 담는 등의 로직을 종종 사용한다.
let names = [];
for (const p of products) {
    names.push(p.name);
}
log(names);

let prices = [];
for (const p of products) {
    prices.push(p.price);
}
log(prices);
  • 위의 log(names)와 같은 함수 직접적으로 어떠한 명령을 일으켜서 함수 외부의 영역에 변화를 일으킨다.
  • 하지만 함수형 프로그래밍에서는 함수가 인자리턴값으로 소통하는 것을 권장한다. -> 이런 코드를 작성할 때 사용하는 함수가 map함수이다.
const map = (f, iter) => {
    let res = [];
    for (const a of iter) {
        res.push(f(a));
    }
    return res;
};

log(map(p => p.name, products));
    log(map(p => p.price, products));
  • iter : 상품뿐 아니라 어떤 데이터도 받을 수 있도록, iter이란 map함수가 받는 값이 이터러블 프로토콜을 따른다는 것을 의미한다.
  • f : 함수를 인자로 받아 어떤 값을 수정할 것인지 그 함수에 위임한다.
  • return
views
map 함수의 사용
  • 순서대로 map함수를 사용하지 않은 결과값, map함수를 사용한 결과값이다.
  • map이라는 함수의 보조함수를 통해 이 이터러블 안에 있는 값 중 어떠한 것을 수집하겠다고 전달하는 식으로 사용한다.
  • map 함수는 고차함수 : 함수를 값으로 다루면서 내가 원하는 시점에 인자를 전달

이터러블 프로토콜을 따른 map의 다형성

  • map 함수는 이터러블 프로토콜을 따르고 있기 때문에 다형성이 높다.
    log(document.querySelectorAll('*');
    
views
  • 이 결과는 array처럼 생겼다.
  • 하지만 다음의 코드는 에러가 발생한다.
    log(document.querySelectorAll('*').map(el => el.nodeName));
    
  • document.querySelectorAll 은 array를 상속받은 함수가 아니기 때문이다.
  • 그래서 프로토타입에 map 함수가 구현이 되어 있지 않다.
  • 하지만 앞에서 만들었던 map함수를 사용한 코드는 동작한다!
log(map(el => el.nodeName, document.querySelectorAll('*')));
const it = document.querySelectorAll('*')[Symbol.iterator]();
    log(it.next());
    log(it.next());
    log(it.next());
    log(it.next());
    log(it.next());
  • document.querySelectorAll 이 이터러블 프로토콜을 따르고 있기 때문이다.
  • map 함수는 이터러블 프로토콜을 따르는 for of 문을 사용했기 때문에 동작한다.

  • 이터러블 프로토콜을 따르는, 이미 만들어져 있는 모든 값에도 map을 사용할 수 있지만, 제너레이터 함수의 결과물에 대해서도 map을 할 수 있다.
function *gen() {
        yield 2;
        yield 3;
        yield 4;
    }
    log(map(a => a * a, gen())); // 이것도 동작! output : [4, 9, 16]
views
  • 사실상 모든 것들에 대해 map 을 할 수 있다고 볼 수 있다!
  • 앞으로 만들어지는 Web API (자바스크립트에 있는 것이 아니라 브라우저의 값, 헬퍼 함수들) 들이 이터러블 프로토콜을 따르고 있고, 계속해서 그렇게 만들어질 것이기 때문에 이터러블 프로토콜을 따르는 함수들을 사용한다는 것은 앞으로 많은 헬퍼 함수들과의 조합성이 좋아진다는 이야기이다.
  • 프로토타입 기반, 혹은 클래스 기반으로 어떤 뿌리를 가진 카테고리 안에 있는 값만을 사용할 수 있는 기법보다 훨씬 다양성이 높고 유연하다.

####Map

  • 이터러블 가운데 Map 존재
      let m = new Map();
      m.set('a', 10);
      m.set('b', 20);
      const it2 = m[Symbol.iterator]();
      log(it2.next());
      log(it2.next());
      log(it2.next());
    
  • map 함수의 이터러블 값으로도 사용할 수 있다.
    log(new Map(map(([k, a]) => [k, a * 2], m)));
    
views
map 함수를 통해 new Map 생성
  • key와 value를 나눠서 받을 수 있다.
  • 다시 Map 객체를 만들 수도 있다.
  • 안쪽에 있는 값이 바뀐 Map 객체를 만드는 데에 이런 방식으로 조합할 수도 있다.

filter

  • 특정 조건을 만족하는 데이터들을 걸러내는 코드
      let under20000 = [];
      for (const p of products) {
          if (p.price < 20000) under20000.push(p);
      }
      log(...under20000);
    
  • 이런 식의 작업을 수행한다.
  • 그러나, 위처럼 코딩하게 되면 다른 조건의 작업을 수행한다고 했을 때 코드의 변경과 중복이 발생한다.
let over20000 = [];
for (const p of products) {
    if (p.price >= 20000) over20000.push(p);
}
log(...over20000);
const filter = (f, iter) => {
    let res = [];
    for (const a of iter) {
        if (f(a)) res.push(a);
    }
    return res;
};
log(...filter(p => p.price < 20000, products));
log(...filter(p => p.price >= 20000, products));
  • 어떤 조건으로 필터링할 것인지는 보조함수에 위임한다.
views
filter
  • array에 대해서도 가능하다.
    log(filter(n => n % 2, [1, 2, 3, 4]));
    
views
array에 filter 적용
  • 즉시실행함수와의 결합도 가능하다.
    log(filter(n => n % 2, function *() {
      yield 1;
      yield 2;
      yield 3;
      yield 4;
      yield 5;
    } ()));
    
views
즉시실행함수에 filter 적용
  • 내부에 있는 값의 다형성은 보조함수를 통해 지원하고
  • 외부적 다형서은 이터러블 프로토콜을 따르는 것으로 지원한다.
  • 그럼으로ㅓ써 filter 역시 다양한 것들을 걸러낼 수 있게 된다.

reduce

  • reduce는 이터러블 값을 하나의 다른 값으로 축약하는 함수 ```JavaScript const nums = [1, 2, 3, 4, 5];

let total = 0; for (const n of nums) { total = total + n; } log(total);

- 특정한 값을 순회해나가면서 하나의 값으로 누적해나갈 때, 이런 코드와 이런 패턴을 사용한다.

```JavaScript
const add = (a, b) => a + b;
log(reduce(add, 0, [1, 2, 3, 4, 5]));
  • 위와 같이 reduce 함수를 사용한다고 했을 때, 내부적으로는 다음과 같이 동작한다.
    log(add(add(add(add(add(0, 1), 2), 3), 4), 5));
    
  • 즉, 내부적으로는 초기값에서부터 시작하여 재귀적으로 보조함수를 실행하면서 하나의 값으로 누적해나간다.
    const reduce = (f, acc, iter) => {
      for (const a of iter) {
          acc = f(acc, a);
      }
      return acc;
    };
    
  • acc : 누적값
  • ‘return’ : 외부세상을 직접 변경하는 것이 아니라 리턴
  • 자바스크립트에서의 reduce는 acc를 optional하게 사용할 수 있도록 구현되어 있다.
    log(reduce(add, [1, 2, 3, 4, 5]));
    
  • 위와 같이 시작하는 값을 생략했을 경우,
    log(reduce(add, 1, [2, 3, 4, 5]));
    
  • 이렇게 받은 것처럼 동작한다.
  • 즉, 이터러블의 첫번째 값 시작값으로 하여 동작한다.
  • 이를 반영한 코드는 다음과 같다.
    const reduce = (f, acc, iter) => {
      if (!iter) { // iter 값이 없다면 acc이 생략된 것
          iter = acc[Symbol.iterator](); // 이터러블 값으로 변경
          acc = iter.next().value; // 이터러블의 첫 번째 값으로 초기화
      }
      for (const a of iter) {
          acc = f(acc, a);
      }
      return acc;
    };
    
  • 숫자만 들어 있는 데이터 외에, 복잡한 데이터 역시 축약할 수 있다.
  • products에 있는 모든 데이터를 reduce를 이용해 더하는 코드
    log(
      reduce(
          (total_price, product) => total_price + product.price,
      0,
      products));
    
  • reduce 함수의 경우에도 역시 보조함수를 통해 내부적 다형성을, 이터러블을 통하여 외부적 다형성을 지원한다.

map+filter+reduce 중첩 사용과 함수형 사고

  • 20000원 미만의 모든 상품들의 가격을 합친 값을 도출하는 코드 작성
      const add = (a, b) => a + b;
    
      log(
          reduce(
              add,
              map(p => p.price,
                  filter(p => p.price < 20000, products))));
    
  • 이 코드를 오른쪽에서 왼쪽으로 읽어나가면 쉽다!
  • filter -> map -> add로 reduce하여 출력(log)
log(
    reduce(
        add,
        filter(n => n < 20000,
            map(p => p.price, products))));
  • 순서를 바꾸어 작성할 수도 있다.
  • 함수들을 중첩하고 함수를 연속적으로 실행하면서 어떤 값으로부터 출발하여 필터링, 그 다음 사용하기 좋은 값으로 추출하고 reduce를 통해 축약해나가면서 원하는 일을 하는 식으로 작성한다.
  • 이렇게 작성할 때 좀더 함수적으로 이 코드를 읽거나 사고하려면? 1) reduce를 하고 싶은데 add를 하는 reduce를 하고 싶다
    log(
      reduce(
        add,
        [10, 20, 30, 40]
      )
    );
    

    2) 숫자가 들어 있는 배열이 평가될 것으로 생각하면서 코드를 작성한 상태에서 이 자리에 숫자가 들어 있는 배열로 평가되도록 코드를 작성해 나간다.

    log(
      reduce(
        add,
        map(p => p.price, products)
      )
    );
    

    3) 마찬가지로, map(p => p.price, products) 에서의 products가 특정 조건들만 남겨져 있을 것으로 평가되도록 작성하면 ok

    log(
      reduce(
        add,
        map(
          p => p.price,
          filter(p => p.price < 20000, products)
        )
      )
    );
    

200304TIL

|

오늘 한 것

  • 지원서 제출
  • 자바스크립트 함수형 프로그래밍 강의 4강 수강 및 정리

회고

map, filter, reduce는 이전에도 파이썬으로 학습해본 바가 있지만, 그를 어떻게 활용해야 할지 막막한 경우가 종종 있었는데 이 강의를 들으며 어떻게 함수형으로 사고하는지를 배웠다. 슬슬 이전에 진행하던 토이 프로젝트를 마무리지어야 할 것 같다. 다음주부터는 코딩테스트 문제도 한두개씩 풀기.