ES5+함수형-함수형으로 전환하기

자바스크립트로 알아보는 함수형 프로그래밍 (ES5) 강의를 수강하며 정리한 내용입니다.

1. 회원 목록, map, filter

var users = [
  { id: 1, name: 'ID', age: 36 },
  { id: 2, name: 'BJ', age: 32 },
  { id: 3, name: 'JM', age: 32 },
  { id: 4, name: 'PJ', age: 27 },
  { id: 5, name: 'HA', age: 25 },
  { id: 6, name: 'JE', age: 26 },
  { id: 7, name: 'JI', age: 31 },
  { id: 8, name: 'MP', age: 23 }
];

// 1. 명령형 코드

  // 1) 30세 이상인 users를 거른다.
  var temp_users = [];
  for (var i = 0; i < users.length; i++) {
      if (users[i].age >= 30) {
          temp_users.push(users[i]);
      }
  }
  console.log(temp_users);

  // 2) 30세 이상인 users의 names를 수집한다.
  var names = [];
  for (var i = 0; i < temp_users.length; i++) {
      names.push(temp_users[i].name);
  }
  console.log(names);

  // 3) 30세 미만인 users를 거른다.
  var temp_users = [];
  for (var i = 0; i < users.length; i++) {
      if (users[i].age < 30) {
          temp_users.push(users[i]);
      }
  }
  console.log(temp_users);

  // 4) 30세 미만인 users의 ages를 수집한다.
  var ages = [];
  for (var i = 0; i < temp_users.length; i++) {
      ages.push(temp_users[i].ages);
  }
  console.log(ages);


// 2. _filter, _map으로 리팩토링
/* 
조건을 제외한 모든 중복을 제거.
추상화의 단위가 함수.

응용형 함수(프로그래밍) : 함수가 함수를 받아서 원하는 시점에 해당하는 함수가 알고 있는 인자를 적용하는 식으로 프로그래밍

고차 함수 : 함수를 인자를 받거나 함수를 리턴하거나 함수안에서 인자로 받은 함수를 실행하는 함수 

데이터형이 어떻게 생겼는지 보이지 않는다. 
다형성이 굉장히 높고, 관심사가 완전히 분리되며 재사용성이 높아진다. */

/* ===================_filter 함수========================== */
function _filter(list, predi) { 
  // list : 무엇을 푸쉬를 할 것인가
  // predi : 무엇을 수집해서 넣을 것인가를 완전히 위임
  var new_list = [];
  for (var i = 0; i < list.length; i++) {
      if (predi(list[i])) {
          new_list.push(list[i]);
      }
  }
  return new_list; // console의 부수효과를 return으로 없앤다.
}

/* 과정
_filter 함수는 user 함수를 받고 유저의 크기만큼 루프를 돌고
해당번째 users를 받아두고 predi 함수에 연속적으로 전달  */

/* ===================_map 함수========================== */
function _map(list, mapper) { 
  // list : 무엇을 푸쉬를 할 것인가
  // mapper : 무엇을 수집해서 넣을 것인가를 완전히 위임
  var new_list = [];
  for (var i = 0; i < list.length; i++) {
    new_list.push(mapper(list[i]));
  }
  return new_list; // console의 부수효과를 return으로 없앤다.
}

console.log(
	_map(
    	_filter(users, function(user) { return user.age >= 30; });
      	function(user) { return user.name; }));

console.log(
	_map(
    	_filter(users, function(user) { return user.age < 30; });
      	function(user) { return user.age; }));


/* ===================다양한 역할========================== */
// _filter과 _map 함수는 users만을 위한 함수가 아니라 다양한 역할을 한다.
console.log(
	_filter([1, 2, 3, 4], function(num) { return num % 2; }));
// [1, 3]

console.log(
	_filter([1, 2, 3, 4], function(num) { return !(num % 2); }));
// [2, 4]

console.log(
	_map([1, 2, 3], function(num) { return num * 2; }));
// [2, 4, 6]

2. each

// 1. _each로 _map, _filter 중복 제거

// 루프부분과 해당 i번째 값을 참조하는 부분의 중복 제거

/* ===================기존 코드========================== */
function _filter(list, predi) { 
  var new_list = [];
  for (var i = 0; i < list.length; i++) {
      if (predi(list[i])) {
          new_list.push(list[i]);
      }
  }
  return new_list;
}

function _map(list, mapper) { 
  var new_list = [];
  for (var i = 0; i < list.length; i++) {
    new_list.push(mapper(list[i]));
  }
  return new_list;
}

/* ===================중복 제거========================== */

function _filter(list, predi) { 
  var new_list = [];
  _each(list, function(val) {
    if (predi(val)) new_list.push(val);
  });
  return new_list;
}

function _map(list, mapper) { 
  var new_list = [];
  _each(list, function(val) {
    new_list.push(mapper(val));
  });
  return new_list;
}

function _each(list, iter) {
	for (var i = 0; i < list.length; i++) {
    	iter(list[i]);
    }
  	return list;
}

3. 다형성

1) filter, map 메서드

순수 함수가 아니고 객체 상태에 따라 결과가 달라진다 (객체 지향)
해당 클래스에 정의되기 때문에 해당 클래스의 인스턴스에서만 사용 된다.
(ex. 배열에서만 사용가능)

/* 데이터가 있어야 메서드가 생긴다.
평가의 순서가 중요.
해당 객체가 생겨야 기능수행이 가능 */
console.log(
	[1, 2, 3, 4].filter(function(val) {
    	return val % 2;
    })
); // [1, 3]

console.log(
	[1, 2, 3, 4].map(function(val) {
    	return val * 2;
    })
); // [2, 4, 6, 8]

2) 외부 다형성

array_like, arguments, documentquerySelectorAll

// documentquerySelectorAll 은 배열처럼 보인다.
console.log( documentquerySelectorAll('*') );
// [html, head, meta ...]

/* documentquerySelectorAll 는 배열이 아니고
array_like 객체이다. (Constructor: NodeList) */
console.log(
	documentquerySelectorAll('*').map(function(node) {
    	return node.nodeName;
    })
); // TypeError: map is not a function

/* 함수는 단독으로 존재하기 때문에 데이터가 생기지 않더라도
평가시점이 유연해져 조합성이 높아진다. */
console.log(
	_map(documentquerySelectorAll('*'), function(node) {
    	return node.nodeName;
    })
); // [html, head, meta ...]

3) 내부 다형성

함수의 두번째 인자(보조함수)를 무조건 콜백함수로 불러주는 것보다
각각의 역할로 불러주는 것이 좋다.

내부의 값에 대한 다형성은 보조함수가 책임을 진다.
ex) predi, iter, mapper

_map([1, 2, 3, 4], function(v) {
	return v + 10;
});

4. 커링, curry, curryr

1) 커링

함수와 인자를 다루는 기법.
함수의 인자를 하나씩 적용해 나가다가
필요한 인자가 모두 채워지면 함수 본체를 실행하는 기법.

2) curry

3) curryr

5. reduce

6. 파이프라인, _go, _pipe, 화살표 함수

7. 다형성 높이기, _keys, 에러

좋은 웹페이지 즐겨찾기