명령형 코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | 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. 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].age); } console.log(ages); | cs |
설명
명령형, 객체지향에서는 데이터를 먼저 준비한다.
데이터셋의 구성이 끝나면 해당 데이터의 행동(메서드를) 정의하며 프로그램 로직을 완성해 나간다.
위의 예시를 살펴보면 식별번호, 이름, 나이 정보를 갖는 오브젝트의 배열을 먼저 준비했다.
이후 해당 배열에서 30세 이상, 30세 미만인 그룹의 이름과 나이를 수집하여 출력하는 로직을 구현했다.
문제점
1. 1,3번 로직에서는 if문의 조건절을 제외하고 코드가 중복된다.
2. 2,4번 로직에서는 어떤 필드를 수집할지를 지정하는 push() 메소드의 내부를 제외하고 코드가 중복된다.
_filter, _map으로 리펙토링
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | function _filter( list, predi ) { var new_list = []; for ( var i = 0; i < list.length; i++ ) { /* 추상화의 단위를 객체나 클래스가 아닌 함수로 이용해서 프로그래밍하는 것이 함수형 프로그래밍 이 부분을 어떤 함수에게 완전히 위임해서 어떤 조건일 때 필터링 할 지를 결정 if ( list[i].age >= 30 ) { new_list.push( list[i] ); }*/ if ( predi(list[i]) ) { new_list.push( list[i] ); } } // 부수효과인 console.log를 제거하고 return으로 변환 // console.log(new_list); 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; } var over_30 = _filter( users, function(user) { return user.age >= 30; }); console.log( over_30 ); var names = _map(over_30, function(user) { return user.name; }); console.log( names ); var under_30 = _filter( users, function(user) { return user.age < 30; }); console.log( under_30 ); var ages = _map(under_30, function(user) { return user.age; }); console.log( ages ); /* _filter, _map은 데이터 형태와 관계없이 재사용성이 높은 함수가 되었음 */ console.log( // 짝수 _filter([1, 2, 3, 4], function(num) { return ( num % 2 == 0 ); }) ); console.log( // 홀수 _filter([1, 2, 3, 4], function(num) { return !( num % 2 == 0 ); }) ); console.log( // 배수 _map([1, 2, 3, 4], function(num) { return num * 2; }) ); | cs |
설명
우선 함수형 프로그래밍에서는 추상화의 단위를 클래스가 아닌 함수로 정의한다.
또한 불변성을 위해 원래 있는 값을 변경하지 않고, 새로운 객체를 만들어서 반환한다.
걸러내기(필터링)을 위한 _filter() 메소드와 수집하기를 위한 _map()메소드를 정의한다.
첫번째 인자로는 데이터를 전달받고, 두 번째 인자로는 함수 내부에서 호출할 함수를 전달받는다.
이처럼 함수가 함수를 받아서 원하는 시점에 해당하는 함수가 알고있는 인자를 적용(평가)하는 함수를 응용형 함수라고 한다.
응용형(적용형) 프로그래밍은 위와같은 응용형 함수를 이용해서 프로그램 로직을 완성해 나가는 방식이다.
고차 함수는 함수를 인자로 받거나, 함수를 리턴하거나, 함수 내부에서 인자로 받은 함수를 호출하는 함수를 의미한다.
결국, _filter, _map 메소드는 응용형 함수이자 고차 함수이다.
_filter()
1 2 3 4 5 6 7 | if ( list[i].age >= 30 ) { over_30.push( list[i] ); } if ( list[i].age < 30 ) { under_30.push( list[i] ); } | cs |
나이가 30세 이상, 30세 미만인 사람들을 걸러내기 위한 조건절이다.
중복되는 부분을 제거하기 위해 predicate(참, 거짓)에 해당하는 함수를 두 번째 인자로 받는다.
즉, 조건절을 _filter함수에게 위임해서 어떤 조건일 때 필터링 할 것인가를 결정한다.
_map()
1 2 3 4 | names.push(over_30[i].name); ages.push(under_30[i].age); | cs |
나이가 30세 이상인 사람들의 이름, 30세 미만인 사람들의 나이를 수집하기 위한 명령문이다.
마찬가지로 중복되는 부분을 제거아기 위해 mapper(무언가를 반환하는)에 해당하는 함수를 두 번째 인자로 받는다.
즉, 수집절을 _map함수에게 위임해서 어떤 데이터를 수집할 것인가를 결정한다.
함수형 프로그래밍은 값을 만들어놓고 문장을 내려가면서 변형해나가는 것이 아니라,
함수를 통과해나가면서 한번에 값을 새롭게 만들어낸다
-> 대입문을 줄이면 간결한 코드가 된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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; } ) ); | cs |
'Web > JavaScript' 카테고리의 다른 글
함수형 자바스크립트 5. _reduce, _pipe, _go, 화살표 함수 (0) | 2017.09.30 |
---|---|
함수형 자바스크립트 4. 커링(_curry, _curryr) (0) | 2017.09.25 |
함수형 자바스크립트 3. 반복자(_each)와 내부다형성 (0) | 2017.09.24 |
함수형 자바스크립트 2. 일급함수와 함수형 프로그래밍 (0) | 2017.09.22 |
함수형 자바스크립트 1. 순수함수와 부수효과 (0) | 2017.09.22 |