본문 바로가기
창고(2021년 이전)

[JS] 함수형 프로그래밍 - 2-1_함수형으로 전환하기

by 측면삼각근 2019. 10. 30.
728x90
반응형

함수형 프로그래밍 - 1_개요


함수형 프로그래밍의 예시

//명령형 코드
var temp_user = [];
for(var i = 0 ; i < user.length ; i++){
	if(user[i].age >= 30){
    	temp_user.push(user[i]);
    }
}

위와같은 명령형 코드가 반복될 때, 함수형 코드로 전환할 수 있다.
중복을 줄이고 코드재활용도를 간단히 높일 수 있다.

//2._filter, _map으로 리펙토링

// 함수형 프로그램에서 추상화의 단위는 객체나 메서드나 클래스가 아닌, '함수'의 단위이다.

function _filter(list, predi){//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.log(
	_filter(users, function(user) {return user.age >= 30; } )));
    
 //위의 경우 뿐만아니라 온갖 경우에서 활용할 수 있다.
 //ex
 _filter([1, 2, 3, 4 ], function(num) {return num %2;});
 
 //_map함수
 function _map(list, mapper){
 	var new_list = [];
    for( var i = 0 ; i < list.length ; i++){
    	new_list.push(mapper(list[i]));
    }
    return new_list;
 }
 // _filter 와 _map모두 함수의 다형성이 높고, data가 어떻게 생겼는지에 대해 중요하지 않게된다
 // 재사용성이 극대화 되었다는 것이다.
 
 ex)사용예시
 
 var over_30 = _filter(users,function(user){return user.age >= 30; });
 var names = _map(over_30, function(user){ return user.name; });
 
 _map(_filter(users, function(user){return user.age>=30;}),
		function(user){return user.name;});
 //안정성 높고 test가 쉬운 코드.

_filter와 같은 함수를 응용형 함수 라고 하는데, 함수가 함수를 받아서 원하는 시점에 해당 함수의 인자를 적용하는 식으로 프로그래밍 하는것을 응용형 함수, 응용형 프로그래밍, 적용형 프로그래밍 이라고 말한다.

또한 고차함수 라고 하기도 한다. ( 함수를 인자를 받거나, 함수를 return 하는 함수)

 

_filter와 _map 함수의 중복제거 -> _each함수

filter와 _map함수의 for loop 또한 중복제거를 할 수 있다.

function _each(list, iter){
	for( var i = 0 ; i < list.length ; i ++){
    	iter(list[i]);
    }
    return list;//받는 값을 그대로 return 함
}

// 위 functio을 만들면 for문 대신 each를 사용하며 코드가 간결 해 줄 수 있다.
// 오류 및 실수감소 에 효과적이다.

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

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

다형성

js ES6에 map과 filter가 이미 존재하는데 왜 다시 구현하였을까?
map과 filter는 함수가 아니라 메서드 이다.
map과 filter는 (순수) 함수가 아니라 (객체 상태에 따라 결과가 달라지는)메서드이다.

메서드는 객체지향 프로그래밍이며, 메서드의 특징은, 해당클래스에 정의되어있기때문에 해당 클래스의 인스턴스에서만 활용할 수 있는 특징이있다. ->map과 filter는 Array가 아니면 사용할 수 없다는 뜻이다.
js 에서는 유사배열(array like Object)가 많다. (Jquery 또한 array-like Object ; NodeList 이다.)

console.log(document.querySelectorAll('*') );
//파일 안의 태그들을 담은 array-like object 가 반환됨
// ex) [html, head, meta, title, scirpt ,...]
// Array.isArray -> false!

node를 다룰 때 map이나 filter 메서드를 적용할 수 없다.
따라서 메서드로는 다형성을 지원하기 어렵다.

앞서 코딩한 _map 이란 함수로 코딩을 하게된다면 정상 적용된다. 따라서 보다 다형성이 높게 프로그래밍 할 수 있다!

함수가 먼저 나오는 프로그래밍 -> 데이터가 있기 전부터 함수가 존재함
데이터가 먼저 나오는 프로그래밍 -> 데이터가 있어서 메서드가 만들어지게됨(객체지향적)

메서드 보다 다형성과 실용성 면에서 함수형 프로그램의 장점이 있다.

 

주의할점

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


뒤의 function을 callback함수라고 부르는 경향이 있는데, 함수형 프로그래밍 에서는,  무조건 call back function이 아니라 다양한 (보조함수)이름을 갖을 수 있다..

call back function : 어떠한 작업을 완료하고 return 해주는 function

 


 

내부다형성

고차함수, 응용형 함수들은, 개발자가 넘기는 값과 고차함수에 대한 이해로 보조함수를 정할 수 있다.


커리 - curry

커링은 함수와 인자를 다루는 기법이다.
함수의 인자를 하나씩 적용해 나가다가, 필요한 인자가 채워지면 함수 본체를 실행하는 기법이다.
js에서는 커링이 지원되지 않지만, 커링과 같은 기법을 구현 할 수있다. -이전포스팅 복습겸 읽어보기

function _curry(fn){
	return function(a){
    	return function(b){
        	//미리 받아두었던 함수 본체를 안쪽에서 원하는 시점에 평가함
        	return fn(a, b);
        }
    }
}

var add = _curry(function( a, b ){
	return a + b;
});

var add = add(10);
console.log(add10(5));// 15

console.log(add(5)(3));//8

console.log(add(1,2));//는 function이 return 되어 실행되지 않음.
//실행을 위해서 _curry function의 코드를 바꿀 필요가 있다.
function _curry(fn){
	return function(a,b){
    	return argument.length == 2 ? fn( a,b) : function(b){return fn(a,b);};
    }
}

다른 방식으로 사용한_curry함수의 모습

//오른쪽부터 인자를 적용해 나가는 function
function _curryr(){
	return function(a, b){
    	return argument.length ===2 ? fn(a, b) : function(b){ return fn(b,a) };
    }
}

//아래와 같은 상황에서 쓰인다.
var sub = _curryr(function(a, b){
	return a - b;
});

console.log(sub(10,5));/
var sub10 = sub(10);
console.log(sub10(5)); //5에 10을 빼는 표현과 맞다! '-5'

 

 


_get을 만들어 조금 더 간단하게 하기

function _get(obj, key){
	return obj === null ?  undefined : obj[key];
	//obj가 key로 접근하기 애매한 경우에 에러를 방지하기 위한 함수
}

console.log(user.name);
console.log(_get(user1, 'name')); // 같은 결과를 반환한다.

//하지만 다음과 같은 상황에선
console.log(user[10].name);//undefined의 없는 key이므로 에러! 다음 행이 실행되지 않음
console.log(_get(user1, 'name')); // 에러가 나지 않고 undefined 가 return 된다.
//매우 안정적으로 사용할 수 있다.

_get함수는 또한 curry로 다시 정의할 수 있다.

var _get = _curryr(function(obj, key){
	return obj === null? undefined : obj[key];
});

console.log(_get(user1, 'name');
console.log(_get('name')(users1));
//위와 같은 활용 또한 가능해진다!

//그렇다면 이러한 함수도 가능해진다.
var get_name = _get('name');
console.log(get_name(user1));
console.log(get_name(users[3]));


//또한 _map과 _filter 사용부를 _get 함수를 이용하여 간결하며 안정적인 사용이 가능해진다.
반응형