본문 바로가기

Language/JavaScript(ES6)

[Javascirpt]함수형 자바스크립트 강의 정리

함수형 자바스크립트 뿐만 아니라

자바스크립트 문법에 대해서도 다시 재정립 할 필요를 느꼈다.


함수형 자바스크립트는 true나 false값도 

if문이 아니라 함수로 만들어서 완전히 값들을

분해하고 조립하는 식으로 짜여진다.

 

function _is_object(obj) {
return typeof obj == "object" && !!obj;
}


객체인지 확인하는 코드 역시 함수로 만들었다.


자바스크립트에선


배열 역시 object 타입이다.



고로 배열과 객체는 True를 반환함


function _keys(obj) {
return _is_object(obj) ? Object.keys(obj) : [];
}


다음은 객체의 키를 반환하는 함수이다.

객체 일시 Object.keys메소드를 이용하여 파라미터의 키들을 배열로 반환한다.


파라미터에 배열을 입력 하면 

기존의 배열 값이 속성값이 되고

배열 값마다 순서대로 0부터 시작하는 새로운 키 값이 생긴다.


function _each(list, iter) {
var keys = _keys(list);
for (var i = 0, len = keys.length; i < len; i++) {
iter(list[keys[i]], keys[i]); // iter(속성 값(키 값) , 속성(키))
}
return list;
}


객체나 배열을 반복하기 위해 쓰이는 함수 이다.

iter의 파라미터는 결국 속성과 속성 값이다.


var _get = function(obj, key) {
return obj == null ? undefined : obj[key];
};
console.log(_get(users[0], "age"));

obj와 key값을 파라미터로 넘겨주면 그 결과 값이 나오는 함수이다. 


이를 통해서 리팩토링된 filter와 map, reduce 함수이다.

filter

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

map

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

reduce

function _reduce(list, iter, memo) {
if (arguments.length == 2) {
memo = list[0];
list = _rest(list);
}
_each(list, function(val) {
memo = iter(memo, val);
});
return memo;
}


예시 1번


console.log(
_map(
_filter(users, function(users) {
return users.name[0] == "J";
}),
function(users) {
return users.age;
}
)
);


해당 코드 결과는 name의 첫 글자가 J로 시작하는 user의 나이가 배열로 출력된다.


예시 2번


console.log(
_reduce(
_map(users, function(users) {
return users.id;
}),
function(memo, val) {
return memo + val;
}
)
);



user의 id를 추출하여 모든 id를 더한다.


Currying

커링은 함수를 정의하여 함수로 다시 사용하고

파라미터의 개수에 따라 자유 자재로 사용 하며

파라미터의 순서에 자유를 주기 위해 만들어 졌다.


function _curry(fn) {
return function(a, b) {
return arguments.length == 2
? fn(a, b)
: function(b) {
return fn(a, b);
};
};
}

function _curryr(fn) {
return function(a, b) {
return arguments.length == 2
? fn(a, b)
: function(b) {
return fn(b, a);
};
};
}


_curry는 함수를 받는데 

커링에 달린 익명함수를 리턴하고 그 arugment가 두개라면

_curry로 받은 함수를 (a,b)로 실행하고

만약 그렇지 않다면(하나 일 경우)

하나의 arugment는 들고 있는 채로 

다시 익명함수를 리턴하고 두번째 argument를 받아 리턴하는 형식이다.


 조금 헷갈리는데 다음 예시를 보자

function example() {
return function(a) {
return function(b) {
console.log(a, b);
};
};
}

example()("a")("b");

함수를 리턴하는 함수는 다음과 같이 실행된다.

결국 함수를 리턴하는 함수는

파라미터를 따로 따로 받고

가장 처음 정의되어진 부모 함수는 받은 모든 파라미터를 다룰 수 있게 된다.


pipe & go

함수형 자바스크립트의 강점인 조합성을 극대화 해주는 함수이다.

function _pipe() {
var fns = arguments;
return function(arg) {
return _reduce(
fns,
function(arg, fn) {
return fn(arg);
},
arg
);
};
}

파이프는 argument로 함수를 받는다.

받은 모든 함수는

fns라는 변수에

객체 형식으로 저장되어진다.



console.log(
_pipe(
function(v) {
return v + 1;
},
function(w) {
return w + 2;
},
function(z) {
return z + 3;
}
)("init")
);// init123


위와 같이 실행하게 되는데


초기값을 밖에서 파라미터로 받고 그 값을 누적값으로

변수에 반복해서 들어가게 된다.


function _go(arg) {
var fns = _rest(arguments);
return _pipe.apply(null, fns)(arg);
}


go는 pipe와 같은 기능을 하는데,

다른 점이라면

좀 더 보기 좋은 코드로 구성할 수 있다는점


console.log(
_go(
"init",
function(val) {
return val +1;
},
function(third) {
return third + 2;
}
)
); //init12


받은 파라미터중 첫번째를 제외하고 fns를 받아 pipe함수의 아규먼트로 보냈다.


이 때 받은 argument들은 배열 안에 저장되는데

이를 pipe함수의 아규먼트로 보내기 위해서는 

반복하여 배열 밖으로 꺼내야 한다.


그렇기 때문에

함수 메소드인 apply를 이용했다.


apply메소드는 어떤 함수의 파라미터들을 배열로 받기 때문이다.