본문 바로가기

Language/JavaScript(ES6)

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

1에서 만든 함수를 가지고

값이나 배열을 받는 개량된 함수를 만든다.


map으로 만드는 values 

배열 안에 있는 배열, 혹은 객체를 순회하며 모든 값 or 키값을 받아 배열에 담아 리턴한다.


function _identity(val) {
return val;
}
var _values = _map(_identity);


해당 코드는 다음과 같은데

_identity는 값을 받아 그대로 그 값을 리턴하는 함수이다.

그리고 이 함수를 _map에 파라미터로 넣었다.


일단 이를 이해하기 위해서

_map함수를 다시 보자


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


_map은 아규먼트로

첫번째 배열형태를 가지는 값

두번째 반복하여 실행해 값을 리턴하는 함수를 가진다.


이와 같은 순서라면 사용성이 떨어진다.

list는 어떤 데이터가 오는 가에 따라 다른 동작을 하지만

mapper에서 하고자 하는 것은

값을 받아 그 값을 그대로 리턴하여 list에 push하는 것이다.


그렇기 때문에 _map함수에 curryr을 하였다.


var _map = _curryr(_map)


결국 _map의 mapper함수는 _identity로 고정되어 있고

_values에 어떤 값을 넘기는가에 따라 값이 결정된다.


_values(users[0])
//[1, "ID", 36]


결과는 다음과 같다.

map으로 만드는 pluck

객체를 담은 배열과 그 객체의 키를 주고 리턴값으로 그 객체의 모든 키값을 리턴하는 함수

var _pluck = _curryr(function(data, key) {
return _map(data, _get(key));
});

데이터와 키를 받아 map함수를 리턴 한다.
map의 파라미터로는
data는 배열
key는 _get함수에 파라미터로써 역할을 한다.

배열은 _get(key)함수의 리턴값을 순회하며 리턴할 것이다.
_pluck(users, "age");
//[36, 25, 72, 34, 10, 55, 32, 11]

filter으로 만드는 reject

배열과 어떤 값이 참인지 거짓인지 리턴하는 함수를 받아, 거짓인 함수만을 리턴하는 함수

function _negate(func) {
return function(val) {
return !func(val);
};
}

var _reject = _curryr(function(data, predi) {
return _filter(data, _negate(predi));
});


filter의 반대 역할이라고 보면된다.


그렇기 때문에 필터에서 받은 함수의 값의 반대인 값을 리턴하는 _negate함수를 만들어서 사용했다.


_reject(users, function(users) {
return users.age > 20;
});
// 0: {id: 5, name: "HA", age: 10}
// 1: {id: 8, name: "RG", age: 11}


filter으로 만드는 compact

배열을 받아 그 값이 true할 경우에만 리턴하는 함수

_compact([1,0,-1,[],{},null,undefined,"value"]);
// [1, -1, [], {}, "value"]

false한 값인 0 null undefined는 리턴 되지 않았다.


filter스러운 find, find_index

배열과 조건을 받아 일치하는 첫번째 인자를 리턴하는 함수.

var _find = _curryr(function(list, predi) {
var keys = _keys(list);

for (var i = 0, len = keys.length; i < len; i++) {
var val = list[keys[i]];
if (predi(val)) return val;
}
});
var _find_index = _curryr(function(list, predi) {
var keys = _keys(list);
for (var i = 0, len = keys.length; i < len; i++) {
if (predi(list[keys[i]])) return i;
}
return -1;
});


기존의 filter와는 다르게

새로운 배열을 만들어 담아두는 것이 아니라

if문을 통과할 시에 val를 리턴하고 반복을 종료하는 함수이다.


_find(users, function(users) {
return users.age < 20;
});
//{id: 5, name: "HA", age: 10}
_find_index(users, function(users) {
return users.age < 20;
});
//4

filter스러운 some,every

조건을 만족하는 함수가 있는가를 판단 하고 있다면 true혹은 false를 반환하는 함수

var _some = _curryr(function(data, predi) {
return _find_index(data, predi || _identity) != -1;
});

var _every = _curryr(function(data, predi) {
return _find_index(data, _negate(predi || _identity)) == -1;
});

위 함수는 find_index를 리턴한다.

find_index는 조건에 만족하는 함수가 몇번째 있는지 리턴하는데

값이 있다면 그 값을 리턴하고

값이 없다면 -1을 리턴 할 것이다.


결국 some은 조건에 맞는 함수를 만나면 true

만나지 못하면 false를 리턴 할 것이고


every는 모든 값이 조건에 맞을시에 true를 리턴 할 것이다.


그리고 만약 두번째 파라미터를 입력하지 않을 시에는 배열 중 

값 자체를 true하냐 false하냐로 판단하여 리턴한다.


var result1 = _some([1, null, 3, 8]); // ture
var result2 = _every([1, null, 3, 8]); // false
var result3 = _some([null, undefined]); // false
var result4 = _every([1, "2", 3]); // ture


뿐만 아니라 객체도 컨드롤 가능하다. 


_some(users, function(user) {
return user.age > 15; //true
_some(users, function(user) {
return user.age < 15; //true
}),
_every(users, function(user) {
return user.age > 15; //false
}),
_every(users, function(user) {
return user.age < 15; //false
})
_find(users, function(user) {
return user.age > 15; //{ id: 1, name: 'ID', age: 36 }
}),
_find(users, function(user) {
return user.age < 15; //{ id: 5, name: 'HA', age: 10 }
}),
_find_index(users, function(user) {
return user.age > 15; //0
}),
_find_index(users, function(user) {
return user.age < 15; //4
})


go 함수로 조합적인 함수도 만들 수 있다


_go(
users,
_some(function(user) {
return user.age > 15;
}),
console.log
);
_go(
users,
_every(function(user) {
return user.age > 15;
}),
console.log
);
_go(
users,
_find(function(user) {
return user.age > 15;
}),
console.log
);
_go(
users,
_find_index(function(user) {
return user.age > 15;
}),
console.log
);


reject로 만든 max min max_by min_by

최소값과 최대값을 찾는 함수.

function _min(data) {
return _reduce(data, function(a, b) {
return a < b ? a : b;
});
}

function _max(data) {
return _reduce(data, function(a, b) {
return a > b ? a : b;
});
}
_min([1, 2, 3, 4, 5]); //1
_max([1, 2, 3, 4, 5]); //5

reduce 함수를 이용해서 memo의 값을 바꿔가며 크기를 비교한 값을 저장하는 식이다.

function _min_by(data, iter) {
return _reduce(data, function(a, b) {
return iter(a) < iter(b) ? a : b;
});
}

function _max_by(data, iter) {
return _reduce(data, function(a, b) {
return iter(a) > iter(b) ? a : b;
});
}

max와 min에서 반복할 함수를 추가로 받아서 어떤 조건을 주는 함수이다.
_min_by([1, 2, 3, 4, 5], function(val) {
return val * -1;
}) // 5
_max_by([1, 2, 3, 4, 5], function(val) {
return val * -1;
}) // 1

value가 음수가 된다면...

go함수를 이용하여 또 사용할 수 있다.
_go(
users,
_filter(user => user.age >= 30),
_min_by(user => user.age),
_get("id"),
console.log
);
_go(
users,
_filter(user => user.age >= 30),
_max_by(_get("age")),
_get("name"),
console.log
);