_ == _.partial입니다. _.partial을 _로 짧게 줄여서 사용할 수 있습니다.
1
2
3
4
5
6
7
8
functionadd(a, b) {
return a + b;
}
var add10 = _(add, 10);
var result = add10(5);
console.log(result);
// 15
_.partial 혹은 _를 실행하면서 인자 자리에 자기 자신인 _를 넘기면 부분 적용할 인자를 건너띌 수 있습니다. _를 이용하면 원하는 곳에만 인자를 부분 적용해둘 수 있습니다. _가 있는 자리는 이후 실행시 채워집니다.
1
2
3
4
5
6
7
8
functionsub(a, b) {
return a - b;
}
var sub10 = _.partial(sub, _, 10);
var result = sub10(20);
console.log(result);
// 10
___
부분 적용의 새로운 구분자인 ___를 활용하면 중간 지점에 인자가 가변적으로 적용되도록 비워둘 수 있습니다. 이것을 이용해 맨 오른쪽 인자나 맨 오른쪽에서 두 번째에만 인자를 적용해두는 것도 가능합니다. ___를 기준으로 왼편의 인자들을 왼쪽부터 적용하고 오른편의 인자들을 오른쪽부터 적용할 준비를 해둔 함수를 리턴합니다. 부분 적용된 함수를 나중에 실행하면 그때 받은 인자들로 왼쪽과 오른쪽을 먼저 채운 후, 남은 인자들로 가운데 ___ 자리를 채웁니다.
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
var pc = _.partial(console.log, ___, 2, 3);
pc(1);
// 결과: 1 2 3
// ___ 자리에 1이 들어가고 2, 3은 맨 오른쪽에 들어갑니다.
pc(1, 4, 5, 6);
// 결과: 1 4 5 6 2 3
// ___ 자리에 1, 4, 5, 6이 들어가고 2, 3은 맨 오른쪽에 들어갑니다.
var pc = _.partial(console.log, _, 2, ___, 6);
pc(1, 3, 4, 5);
// 결과: 1 2 3 4 5 6
// _에 1이 들어가고 2를 넘어가고 ___ 자리에 3, 4, 5가 채워지고 6이 맨 오른쪽에 들어갑니다.
pc(1, 3, 4, 5, 7, 8, 9);
// 결과: 1 2 3 4 5 7 8 9 6
// _에 1이 들어가고 2를 넘어가고 ___ 자리에 3, 4, 5, 7, 8, 9가 채워지고 6이 맨 오른쪽에 들어갑니다.
var pc = _.partial(console.log, _, 2, ___, 5, _, 7);
pc(1);
// 결과: 1 2 5 undefined 7
// _ 자리에 1이 들어가고 2와 5사이는 유동적이므로 모이고 5가 들어간 후 _가 undefined로 대체 되고 7이 들어갑니다.
pc(1, 3, 4);
// 결과: 1 2 3 5 4 7
// _ 자리에 1이 들어가고 2와 5사이에 3이 들어가고 _ 를 4로 채운 후 7이 들어갑니다.
// 왼쪽의 _ 들이 우선 순위가 제일 높고 ___ 보다 오른쪽의 _ 들이 우선순위가 높습니다.
pc(1, 3, 4, 6, 8);
// 결과: 1 2 3 4 6 5 8 7
// _ 자리에 1이 들어가고 2와 5사이에 3, 4, 6이 들어가고 _ 를 8로 채운 후 7이 들어갑니다.
Pipe
_.pipe
_.pipe는 함수들을 모아서 하나의 함수로 합성하는 함수입니다. 왼쪽에서 오른쪽으로 실행됩니다. _.pipe를 __로 짧게 줄여서 사용할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
functionsum(a, b) {
return a + b;
}
functionsquare(a) {
return a * a;
}
var f1 = _.pipe(sum, square, square);
var result = f1(1, 2)
console.log(result);
// 81
_.go
_.go는 파이프라인의 즉시 실행 버전입니다. 첫 번째 인자로 받은 값을 두 번째 인자로 받은 함수에게 넘겨주고 두 번째 인자로 받은 함수의 결과는 세 번째 함수에게 넘겨주는 것을 반복하다가 마지막 함수의 결과를 리턴해줍니다.
1
2
3
4
5
6
7
_.go(10, // 첫 번째 함수에서 사용할 인자
function(a) { return a * 10 }, // 연속 실행할 함수 1
// 100
function(a) { return a - 50 }, // 연속 실행할 함수 2
// 50
function(a) { return a + 10 }); // 연속 실행할 함수 3
// 60
_.mr
Partial.js의 파이프라인 함수들은 Multiple Results를 지원합니다. _.mr 함수를 함께 사용하면 다음 함수에게 2개 이상의 인자들을 전달할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
_.go(10, // 첫 번째 함수에서 사용할 인자
function(a) { return _.mr(a * 10, 50) }, // 두 개의 값을 리턴
function(a, b) { return a - b }, // 두 개의 인자 받기
function(a) { return a + 10 });
// 60
_.go(_.mr(2, 3),
function(a, b) {
return a + b; // 2 + 3
},
function(a) {
return a * a;
});
// 25
_.to_mr(array)을 사용하면 배열을 값으로 받아 멀티 리턴 배열(mr)을 만듭니다.
1
2
3
4
_.go(_.mr([2, 3]),
function(a, b) {
return a + b; // 2 + 3
});
_.tap
_.tap은 받아둔 함수들을 모두 실행한 후 처음 받은 인자를 동일하게 리턴하는 파이프라인 함수입니다.
1
2
3
4
5
_.go(10,
_.tap(
function(a) { return a * a },
console.log), // 100
console.log); // 10
_.all
_.all은 같은 인자를 다수의 함수에게 전달하는 함수입니다. 각 함수가 리턴한 값을 모아 다음 함수로 전달합니다.
1
2
3
4
5
_.go(10,
_.all(
function(a) { return a * a },
function(a) { return a - 5 }),
console.log); // 100 5
_.spread
_.spread는 다수의 인자(혹은 Multi Returns)를 순서대로 함수에게 나누어 전달하는 함수입니다. 각 함수가 리턴한 값을 모아 다음 함수로 전달합니다.
1
2
3
4
5
_.go(_.mr(10, 20),
_.spread(
function(a) { return a * a },
function(a) { return a * a }),
console.log); // 100 400
Collections
_.each
_.each(list, iteratee) 리스트를 끝까지 순회하며 함수를 실행합니다.
1
2
3
4
_.each([1,2,3], alert);
// alert 함수가 각 번호에 맞춰 실행됩니다.
_.each({one: 1, two: 2, three: 3}, alert)
// alert 함수가 각 번호 값에 맞춰 실행됩니다.
_.map
_.map(list, iteratee) 리스트를 순회하며 주어진 함수로 새로운 배열을 생성합니다.
1
2
3
4
5
6
_.map([1,2,3], function(num) { return num * 3; });
_.indexOf(array, value, [isSorted]) 배열을 순서대로 탐색해 value와 일치하는 값의 인덱스를 찾습니다. 일치하는 값을 찾을 수 없다면 -1을 반환합니다. 정렬된 배열이라면 isSorted에 true를 전달함으로써 보다 빠른 검색이 가능해집니다. 혹은 인덱스 값을 전달해서 탐색을 시작할 위치를 정할 수도 있습니다.
1
2
_.indexOf([1, 2, 3], 2);
// 1
_.lastIndexOf
_.lastIndexOf(array, value, [fromIndex]) 배열의 끝에서부터 탐색해 value와 일치하는 값의 인덱스를 찾습니다. 찾을 수 없다면 -1을 반환합니다. fromIndex값으로 탐색을 시작할 위치 정할 수 있습니다.
1
2
_.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
// 4
_.sortedIndex
_.sortedIndex(list, value, [iteratee]) 리스트를 탐색하며 value가 삽입되었을 때 리스트의 정렬된 상태를 유지할 수 있는 위치의 인덱스를 찾습니다.
_.memoize(function, [hashFunction]) 함수의 리턴 값을 저장하여, 동일한 인자가 들어올 때 저장 값을 리턴합니다
1
2
3
4
5
6
7
8
9
10
var mult5 = _.memoize(function(a) { return a * 5; });
console.log( mult5(1) );
// 본체 실행 1
// 5
console.log( mult5(2) );
// 본체 실행 2
// 10
console.log( mult5(1) );
// 캐시로 결과 바로 리턴 1
// 5
_.memoize2
_.memoize2(function) 불변적으로 값을 다룰 때 성능과 관리가 유용합니다. 불변적으로 값을 다루기만하면 캐시를 비우는 것도 자동으로 이루어집니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var evens = _.memoize2(function(list) {
console.log('함수 본체에 들어와서 loop 실행');
return _.filter(list, function(num) {
return num % 2 == 0;
})
});
var list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
console.log( evens(list) );
// 함수 본체에 들어와서 loop 실행
// [2, 4, 6, 8, 10]
console.log( evens(list) );
// [2, 4, 6, 8, 10] (캐시를 사용하여 loop를 돌지 않음)
list = list.concat(11, 12); // _.memoize2는 불변적으로 값을 다룰 때 성능과 관리가 유용합니다.
console.log( list );
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
console.log( evens(list) );
// 함수 본체에 들어와서 loop 실행
// [2, 4, 6, 8, 10, 12]
console.log( evens(list) );
// [2, 4, 6, 8, 10, 12] (캐시를 사용하여 loop를 돌지 않음)
_.delay
_.delay(function, wait, *arguments) 정해진 시간(wait) 후에 함수가 호출 됩니다. 호출 될 함수의 인자를 옵션으로 받을 수 있습니다
1
2
_.delay(alert, 1000, "alert later");
// 1초 후에 'alert later' 알림 메세지가 나타납니다.
defer
_.defer(function, *arguments) setTimeout 0과 같은 효과입니다. 콜 스택이 다 비워진 후에 함수가 호출 됩니다.
1
2
3
_.defer(function(){ console.log("deferred"); });
console.log("first")
//'first' 후에 'deferred'가 출력됩니다.
_.once
_.once(function) 함수가 한 번만 호출 됩니다. 그 이후의 호출은 효력이 없습니다.
1
2
3
4
5
var oneTime = _.once(function(){ return "only one time"});
oneTime();
//'only one time'
oneTime();
//undefined
_.after
_.after(count, function) 지정한 횟수만큼 호출 후에 함수가 호출 됩니다. 그 이후로는 호출 할때마다 함수가 호출 됩니다.
1
2
3
4
5
var renderNotes = _.after(notes.length, render);
_.each(notes, function(note) {
note.asyncSave({success: renderNotes});
});
// renderNotes는 모든 note가 비동기로 저장된(asyncSave) 후에 한번 호출 됩니다.
_.before
_.before(count, function) 지정 횟수 전까지 함수를 호출 합니다. 그 이후의 호출은 마지막 호출된 값과 같은 결과 값이 나옵니다.
1
2
3
4
5
6
7
var greet = _.before(3, function(when){return'Good '+when+'!'});
greet('morning');
//"Good morning!"
greet('afternoon');
//"Good afternoon!"
greet('evening');
//"Good afternoon!"
_.negate
_.negate(predicate) predicate 함수 결과(true, false)의 반대를 리턴합니다.
1
2
3
var isFalsy = _.negate(Boolean); // Boolean 함수는 인자가 참일때, true, 거짓일때 false를 출력합니다
_.find([-2, -1, 0, 1, 2], isFalsy);
// 0
_.throttle
_.throttle(function, wait, [options])은 함수를 받아 새로운 함수 throttled를 리턴합니다. throttled는 처음 호출할때 바로 실행됩니다. 그 이후의 지정된 시간 동안 반복된 호출은 한번만 실행됩니다. 옵션값인 {leading: false}는 throttled가 처음 실행될 때 기본값과 같이 바로 실행 되는 것이 아니라, 지정한 시간 후에 실행됩니다. {trailing: false}는 지정한 시간 전의 실행은 모두 무효가 됩니다. 즉 throttled가 지정된 시간 전에 반복적으로 호출 되어도 지정된 시간이 지나기 전까지의 호출은 다 무효가 됩니다. 지정된 시간이 지난 후에 호출해야 실행됩니다. 기본 옵션값은 {leading: true, trailing: true}입니다.
1
2
3
var throttled = _.throttle(someFunc, 100);
$(window).scroll(throttled);
//스크롤 할 때, someFunc는 시작할때 한 번 실행된 후 0.1초후에 실행됩니다. 이어서 계속 스크롤 중이라면 0.1초의 간격을 두고 실행됩니다.
_.debounce
_.debounce(function, wait, [immediate])_.debounce는 함수를 받아 새로운 함수 debounced를 리턴합니다. (1)debounced를 실행하면 지정된 시간이 지난 후 받아둔 함수를 실행합니다. 만일 지정된 시간 전에 debounced가 다시 실행되면 함수 실행은 다시 지정된 시간 이후로 미뤄집니다. [immediate]에 true를 넘기면 debounced의 첫 번째 실행은 무조건 실행하고, 그 후 시간 안에 실행된 함수는 무시됩니다.
1
2
3
var debounced = _.debounce(someFunc, 100);
$(window).scroll(debounced);
// 스크롤이 끝나고 나서 0.1초 후에 someFunc가 실행됩니다. 0.1초가 지나기 전에 스크롤을 다시 한다면, 다시 0.1초가 지나야 someFunc가 호출 됩니다.
_.bind
_.bind(function, object, *arguments) 함수와 그 함수의 객체(this)를 지정하여 함수를 만듭니다. 옵션으로 함수의 인자를 받을 수 있습니다.
()를 사용할 때 id로 비교하는 경우에는 #을 사용하는 방식이 성능이 가장 좋습니다. JSON Selector는 ()를 통해 find(predicate)를 작성할 수 있어 단순히 key들로 찾아가는 방법보다 유용합니다. JSON Selector의 ()는 함수이므로, id 비교외에 다른 조건도 얼마든지 만들 수 있습니다.
Mutable
_.set
_.set(object, selector, value)은 첫 번째 인자로 변경할 부모 객체를 받고, 두 번째 인자로 JSON Selector를 받아, 해당 부분의 값을 세 번째 인자로 받은 값으로 변경합니다.
Mutable 함수들 앞에 _.im를 붙이면 깊은 값을 불변적으로 다룰 수 있습니다. 예를 들어 _.im.set은 첫 번째 인자로 변경할 부모 객체를 받고, 두 번째 인자로 JSON Selector를 받아, 해당 부분의 값을 세 번째 인자로 받은 값으로 변경합니다. 단 기존의 값은 변경하지 않고 안쪽 값이 변경된 새로운 부모 객체를 리턴합니다.