Partial

_.partial

_.partial을 통해 인자를 부분 적용해둔 함수를 만들 수 있습니다.

1
2
3
4
5
6
7
8
function add(a, b) {
return a + b;
}
var add10 = _.partial(add, 10);
var result = add10(5);
console.log(result);
// 15

_

_ == _.partial입니다. _.partial_로 짧게 줄여서 사용할 수 있습니다.

1
2
3
4
5
6
7
8
function add(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
function sub(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
function sum(a, b) {
return a + b;
}
function square(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; });
// [3, 6, 9]
_.map({one: 1, two: 2, three: 3}, function(num, key) { return num * 3; });
// [3, 6, 9]
_.map([[1, 2], [3, 4]], _.first);
// [1, 3]

_.reduce

_.reduce(list, iteratee, [memo]) inject 혹은 foldl라고 불리는 이 함수는 리스트를 순회하며 하나의 값을 추출합니다. memo는 옵션값이며 추출될 값의 초기값이 됩니다.

1
2
var sum = _.reduce([1, 2, 3], function(memo, num){ return memo + num; }, 0);
console.log(sum); // 6

_.reduceRight

_.reduceRight(list, iteratee, [memo]) _.reduce와 반대 방향으로 순회하며 하나의 값을 추출합니다.

1
2
3
var list = [[0, 1], [2, 3], [4, 5]];
var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []);
console.log(flat); // [4, 5, 2, 3, 0, 1]

_.find

_.find(list, predicate) 리스트의 내부 값을 관찰하여 predicate의 결과가 참인 값을 반환합니다.

1
2
var even = _.find([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
console.log(even); // 2

_.filter

_.filter(list, predicate) 리스트의 내부 값을 관찰하여 predicate의 결과가 참인 값들을 배열로 반환합니다.

1
2
var evens = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
console.log(evens); // [2, 4, 6]

_.where

_.where(list, properties) 리스트의 내부 값을 관찰하여 프로퍼티를 포함하고 있는 객체들을 배열로 반환합니다.

1
2
_.where(listOfPlays, {author: "Shakespeare", year: 1611});
// [{title: "Cymbeline", author: "Shakespeare", year: 1611}, {title: "The Tempest", author: "Shakespeare", year: 1611}]

_.findWhere

_.findWhere(list, properties) 리스트의 내부 값을 관찰하여 프로퍼티를 포함하고 있는 첫번째 객체를 반환합니다.

1
2
3
4
5
6
7
8
9
_.findWhere(publicServicePulitzers, {newsroom: "The New York Times"});
/*
{
year: 1918, newsroom: "The New York Times",
reason: "For its public service in publishing in full so many official reports,
documents and speeches by European statesmen relating to the progress and
conduct of the war."
}
*/

_.reject

_.reject(list, predicate) 리스트를 순회하며 predicate의 결과가 참인 값들을 제외한 배열을 반환합니다.

1
2
var odds = _.reject([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
console.log(odds); // [1, 3, 5]

_.every

_.every(list, [predicate]) 리스트의 모든 값이 참에 해당하는 값인지 판별합니다. 거짓 값을 발견하면 순회를 멈춥니다.

1
2
_.every([2, 4, 5], function(num) { return num % 2 == 0; });
// false

_.some

_.some(list, [predicate]) 리스트의 값 중 참에 해당하는 값이 하나라도 있다면 참을 반환합니다. 참 값을 발견하면 순회를 멈춥니다.

1
2
_.some([null, 0, 'yes', false]);
// true

_.contains

_.contains(list, value, [fromIndex]) 리스트의 값이 value를 포함한다면 참을 반환합니다.

1
2
_.contains([1, 2, 3], 3);
// true

_.invoke

_.invoke(list, methodName, *arguments) 리스트의 각 값이 가지고 있는 메소드를 실행합니다.

1
2
_.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
// [[1, 5, 7], [1, 2, 3]]

_.pluck

_.pluck(list, propertyName) 프로퍼티의 값만을 추출합니다.

1
2
3
var stooges = [{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}];
_.pluck(stooges, 'name');
// ["moe", "larry", "curly"]

_.max

_.max(list, [iteratee]) 리스트의 값 중 최대값을 반환합니다. 만약 iteratee 함수를 전달하면 해당 함수가 최대값이 될 기준을 정합니다.

1
2
3
var stooges = [{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}];
_.max(stooges, function(stooge){ return stooge.age; });
// {name: 'curly', age: 60}

_.min

_.min(list, [iteratee]) 리스트의 값 중 최소값을 반환합니다. 만약 iteratee 함수를 전달하면 해당 함수가 최소값이 될 기준을 정합니다.

1
2
3
var numbers = [10, 5, 100, 2, 1000];
_.min(numbers);
// 2

_.sortBy

_.sortBy(list, iteratee) 리스트의 값들을 정렬합니다.

1
2
3
4
5
6
_.sortBy([1, 2, 3, 4, 5, 6], function(num){ return Math.sin(num); });
// [5, 4, 6, 3, 1, 2]
var stooges = [{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}];
_.sortBy(stooges, 'name');
// [{name: 'curly', age: 60}, {name: 'larry', age: 50}, {name: 'moe', age: 40}];

_.groupBy

_.groupBy(list, iteratee) 리스트의 값들을 iteratee를 통해 특정 집합으로 분류합니다.

1
2
3
4
5
_.groupBy([1.3, 2.1, 2.4], function(num){ return Math.floor(num); });
// {1: [1.3], 2: [2.1, 2.4]}
_.groupBy(['one', 'two', 'three'], 'length');
// {3: ["one", "two"], 5: ["three"]}

_.indexBy

_.indexBy(list, iteratee) 특정 리스트의 값을 인덱스 값으로 반영한 객체를 반환합니다. _.groupBy와 비슷하지만 알고 있는 키의 값이 유니크 할 때 사용합니다.

1
2
3
4
5
6
7
8
9
var stooges = [{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}];
_.indexBy(stooges, 'age');
/*
{
"40": {name: 'moe', age: 40},
"50": {name: 'larry', age: 50},
"60": {name: 'curly', age: 60}
}
*/

_.countBy

_.countBy(list, iteratee) 리스트의 값들을 iteratee를 통해 분류된 값의 개수 정리한 객체를 반환합니다.

1
2
3
4
_.countBy([1, 2, 3, 4, 5], function(num) {
return num % 2 == 0 ? 'even': 'odd';
});
// {odd: 3, even: 2}

_.shuffle

_.shuffle(list) 리스트의 값의 순서를 섞은 사본을 반환합니다.

1
2
_.shuffle([1, 2, 3, 4, 5, 6]);
// [4, 1, 6, 3, 5, 2]

_.sample

_.sample(list, [n]) 리스트에서 임의의 샘플을 반환합니다. 옵션 값인 n값을 통해 샘플의 수를 정할 수 있습니다.

1
2
3
4
5
_.sample([1, 2, 3, 4, 5, 6]);
// 4
_.sample([1, 2, 3, 4, 5, 6], 3);
// [1, 6, 2]

_.toArray

_.toArray(list) 리스트를 진짜 배열로 만들어줍니다. arguments 객체를 변경할 때 유용합니다.

1
2
(function(){ return _.toArray(arguments).slice(1); })(1, 2, 3, 4);
// [2, 3, 4]

_.size

_.size(list) 리스트에 있는 값의 개수를 반환합니다.

1
2
_.size({one: 1, two: 2, three: 3});
// 3

_.partition

_.partition(array, predicate) 하나의 배열을 predicate를 만족하는 배열과 그렇지 않은 배열로 나눕니다.

1
2
_.partition([0, 1, 2, 3, 4, 5], isOdd);
// [[1, 3, 5], [0, 2, 4]]

_.sum

_.sum(array, iteratee) 배열의 내부 값에 iteratee를 적용한 값들을 더합니다.

1
2
3
4
5
6
7
8
_.sum([1, 2, 3], function(v) {
return v * 10;
});
// 60
_.sum(['a', 'b', 'c'], function(v) {
return v.toUpperCase();
});
// ABC

Array

_.first

_.first(array, [n]) 배열의 첫번째 요소를 반환합니다. n으로 몇개까지 반환할지 결정할 수 있습니다.

1
_.first([5, 4, 3, 2, 1]); // 5

_.initial

_.initial(array, [n]) 배열의 마지막 요소만 제외한 배열을 반환합니다.

1
_.initial([5, 4, 3, 2, 1]); // [5, 4, 3, 2]

_.last

_.last(array, [n]) 배열의 마지막 요소를 반환합니다. n으로 몇개까지 반환할지 결정할 수 있습니다.

1
_.last([5, 4, 3, 2, 1]); // 1

_.rest

_.rest(array, [n]) 배열의 첫번째 요소만 제외한 배열을 반환합니다.

1
_.rest([5, 4, 3, 2, 1]); // [4, 3, 2, 1]

_.compact

_.compact(array) 배열의 모든 거짓 값을 제거한 배열의 사본을 반환합니다.

1
_.compact([0, 1, false, 2, '', 3]); // [1, 2, 3]

_.flatten

_.flatten(array, [noDeep]) 중첩 배열(nested array)을 풀어냅니다. 만약에 noDeep을 전달하면 배열을 한단계만 풉니다.

1
2
3
4
5
_.flatten([1, [2], [3, [[4]]]]);
// [1, 2, 3, 4];
_.flatten([1, [2], [3, [[4]]]], true);
// [1, 2, 3, [[4]]];

_.without

_.without(array, *values) values와 같은 값이 제거된 배열의 사본을 반환합니다.

1
2
_.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
// [2, 3, 4]

_.union

_.union(*arrays) 배열들의 값을 확인하여 하나의 합집합 배열을 만듭니다.

1
2
_.union([1, 2, 3], [101, 2, 1, 10], [2, 1]);
// [1, 2, 3, 101, 10]

_.intersection

_.intersection(*arrays) 배열들의 값을 확인하여 하나의 교집합 배열을 만듭니다.

1
2
_.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]);
// [1, 2]

_.difference

_.difference(array, *others) 첫번째 배열과 비교하여 하나의 차집합 배열을 만듭니다.

1
2
_.difference([1, 2, 3, 4, 5], [5, 2, 10]);
// [1, 3, 4]

_.uniq

_.uniq(array, [iteratee]) 배열에서 중복을 제거된 상태의 배열을 만듭니다.

1
2
_.uniq([1, 2, 1, 4, 1, 3]);
// [1, 2, 4, 3]

_.zip

_.zip(*arrays) 배열들의 값 중 인덱스가 동일한 값끼리 묶은 다중 배열을 만듭니다.

1
2
_.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]);
// [["moe", 30, true], ["larry", 40, false], ["curly", 50, false]]

_.unzip

_.unzip(array) 인자로 전달된 다중 배열에서 인덱스가 동일한 값끼리 재배열한 다중 배열을 만듭니다.

1
2
_.unzip([["moe", 30, true], ["larry", 40, false], ["curly", 50, false]]);
// [['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]]

_.object

_.object(list, [values]) 배열을 객체로 만듭니다. 키가 될 배열과 값이 될 배열을 인자로 함께 전달하거나 하나의 배열에 키와 값을 쌍으로 가진 복수의 배열을 전달할 수 있습니다.

1
2
3
4
5
_.object(['moe', 'larry', 'curly'], [30, 40, 50]);
// {moe: 30, larry: 40, curly: 50}
_.object([['moe', 30], ['larry', 40], ['curly', 50]]);
// {moe: 30, larry: 40, curly: 50}

_.indexOf

_.indexOf(array, value, [isSorted]) 배열을 순서대로 탐색해 value와 일치하는 값의 인덱스를 찾습니다. 일치하는 값을 찾을 수 없다면 -1을 반환합니다. 정렬된 배열이라면 isSortedtrue를 전달함으로써 보다 빠른 검색이 가능해집니다. 혹은 인덱스 값을 전달해서 탐색을 시작할 위치를 정할 수도 있습니다.

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가 삽입되었을 때 리스트의 정렬된 상태를 유지할 수 있는 위치의 인덱스를 찾습니다.

1
2
3
4
5
6
_.sortedIndex([10, 20, 30, 40, 50], 35);
// 3
var stooges = [{name: 'moe', age: 40}, {name: 'curly', age: 60}];
_.sortedIndex(stooges, {name: 'larry', age: 50}, 'age');
// 1

_.findIndex

_.findIndex(array, predicate) _.indexOf와 같은 일을 하지만 predicate가 참을 반환하는 값의 인덱스를 찾습니다.

1
2
3
4
_.findIndex([4, 6, 8, 12], isPrime);
// -1
_.findIndex([4, 6, 7, 12], isPrime);
// 2

_.findLastIndex

_.findLastIndex(array, predicate) _.findIndex처럼 predicate가 참을 반환하는 값의 인덱스를 찾지만, 배열의 역순으로 탐색합니다.

1
2
3
4
5
6
var users = [{'id': 1, 'name': 'Bob', 'last': 'Brown'},
{'id': 2, 'name': 'Ted', 'last': 'White'},
{'id': 3, 'name': 'Frank', 'last': 'James'},
{'id': 4, 'name': 'Ted', 'last': 'Jones'}];
_.findLastIndex(users, function(user) { return user.name == 'Ted'; });
// 3

_.range

_.range([start], stop, [step]) 범위를 정해 정수로 구성된 배열을 만듭니다. 값을 하나만 전달하면 0부터 전달된 값 이전까지가 범위가 됩니다.

1
2
3
4
5
6
7
8
9
10
_.range(10);
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
_.range(1, 11);
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
_.range(0, 30, 5);
// [0, 5, 10, 15, 20, 25]
_.range(0, -10, -1);
// [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
_.range(0);
// []

_.remove

_.removelist의 값을 직접 변경합니다. 동일한 값을 지웁니다.

1
2
3
4
var list = [1, 3, 5, 7];
_.remove(list, 5);
console.log(list);
// [1, 3, 7]

_.removeByIndex

_.removeByIndexlist의 값을 직접 변경합니다. 해당하는 번째의 값을 지웁니다.

1
2
3
4
var list = [1, 3, 5, 7];
_.removeByIndex(list, 2);
console.log(list);
// [1, 3, 7]

Object

_.keys

_.keys(object) 객체가 가진 프로퍼티의 이름인 키 값들을 모아 배열을 만듭니다.

1
2
_.keys({one: 1, two: 2, three: 3});
// ["one", "two", "three"]

_.values

_.values(object) 객체가 가진 프로퍼티의 값을 모아 배열을 만듭니다.

1
2
_.values({one: 1, two: 2, three: 3});
// [1, 2, 3]

_.val

_.val(object, key) 객체의 키 값에 해당하는 프로퍼티의 값을 반환합니다. _.val_.v로 짧게 줄여서 사용할 수 있습니다.

1
2
_.val({one: 1, two: 2, three: 3}, 'one');
// 1

_.mapObject

_.mapObject(object, iteratee) _.map과 유사하지만 객체를 만들어줍니다. 객채를 순회하며 각 프로퍼티의 값을 변경합니다.

1
2
3
4
_.mapObject({start: 5, end: 12}, function(val, key) {
return val + 5;
});
// {start: 10, end: 17}

_.pairs

_.pairs(object) 객체를 [key, value]의 형태의 배열들을 가진 다중 배열로 변환합니다.

1
2
_.pairs({one: 1, two: 2, three: 3});
// [["one", 1], ["two", 2], ["three", 3]]

_.invert

_.invert(object) 객체의 프로퍼티 값과 키를 거꾸로 만들어줍니다. 값은 키로 키는 값이 됩니다. 이때 모든 값은 유니크하고 문자열로 나타낼 수 있어야합니다.

1
2
_.invert({Moe: "Moses", Larry: "Louis", Curly: "Jerome"});
// {Moses: "Moe", Louis: "Larry", Jerome: "Curly"};

_.functions

_.functions(object) 객체가 가진 메소드들의 이름을 정렬된 상태의 배열로 반환합니다.

1
2
_.functions(_);
// ["all", "any", "bind", "bindAll", "clone", "compact", "compose" ...

_.findKey

_.findKey(object, predicate) 객체를 위한 _.findIndex입니다. predicate가 참을 반환하는 프로퍼티의 이름인 키를 반환합니다.

1
2
3
4
5
var list = {Moe: "Moses", Larry: "Louis", Curly: "Jerome"};
_.findKey(list, function(val) {
return /oui$/.test(val);
});
// "Larry"

_.extend

_.extend(destination, *sources) sources에 해당하는 객체들의 프로퍼티를 얕게 복사해서 destination에 해당하는 객체에 붙여 객체를 확장합니다.

1
2
_.extend({name: 'moe'}, {age: 50});
// {name: 'moe', age: 50}

_.pick

_.pick(object, *keys) 객체의 프로퍼티 중에서 키가 일치하는 프로퍼티를 뽑은 새로운 객체를 반환합니다.

1
2
3
4
5
6
_.pick({name: 'moe', age: 50, userid: 'moe1'}, ['name', 'age']);
// {name: 'moe', age: 50}
_.pick({name: 'moe', age: 50, userid: 'moe1'}, function(value, key, object) {
return _.isNumber(value);
});
// {age: 50}

_.omit

_.omit(object, *keys) 객체의 프로퍼티 중에서 키가 일치하는 프로퍼티를 빼낸 새로운 객체를 반환합니다.

1
2
3
4
5
6
_.omit({name: 'moe', age: 50, userid: 'moe1'}, 'userid');
// {name: 'moe', age: 50}
_.omit({name: 'moe', age: 50, userid: 'moe1'}, function(value, key, object) {
return _.isNumber(value);
});
// {name: 'moe', userid: 'moe1'}

_.defaults

_.defaults(object, *defaults) 객체의 프로퍼티 중 값이 undefined인 프로퍼티의 값을 defaults객체의 값으로 채웁니다.

1
2
3
var iceCream = {flavor: "chocolate"};
_.defaults(iceCream, {flavor: "vanilla", sprinkles: "lots"});
// {flavor: "chocolate", sprinkles: "lots"}

_.clone

_.clone(object) 얕은 복사로 객체를 복제합니다. 중첩 객체의 경우에는 복제하지 않고 참조합니다.

1
2
_.clone({name: 'moe'});
// {name: 'moe'};

_.has

_.has(object, key) 객체에 특정 키가 존재하는지 확인합니다.

1
2
_.has({a: 1, b: 2, c: 3}, "b");
// true

_.method

_.method(method, [*arguments]) 객체의 메소드를 실행할 함수를 반환합니다. 메소드에게 전달할 arguments도 받습니다.

1
2
3
4
5
6
_.go(
jQuery('body'),
_.method('find', '#main'),
_.first
);
// <div id="main">...</div>

_.isEqual

_.isEqual(object, other) 두 객체의 값을 비교해 같은지 확인합니다.

1
2
3
4
5
6
var stooge = {name: 'moe', luckyNumbers: [13, 27, 34]};
var clone = {name: 'moe', luckyNumbers: [13, 27, 34]};
stooge == clone;
// false
_.isEqual(stooge, clone);
// true

_.isMatch

_.isMatch(object, properties) 두 객체를 비교해 일치하는 프로퍼티가 있는지 확인합니다.

1
2
3
var stooge = {name: 'moe', age: 32};
_.isMatch(stooge, {age: 32});
// true

_.isEmpty

_.isEmpty(object) 객체가 비어있는지 확인합니다.

1
2
3
4
_.isEmpty([1, 2, 3]);
// false
_.isEmpty({});
// true

_.isElement

_.isElement(object) 객체가 DOM 엘리먼트인지 확인합니다.

1
2
_.isElement(jQuery('body')[0]);
// true

_.isArray

_.isArray(object) 객체가 배열인지 확인합니다.

1
2
3
4
(function(){ return _.isArray(arguments); })();
// false
_.isArray([1,2,3]);
// true

_.isObject

_.isObject(value) 값이 객체인지 확인합니다. (자바스크립트에선 배열과 함수도 객체입니다.)

1
2
3
4
_.isObject({});
// true
_.isObject(1);
// false

_.isArguments

_.isArguments(object) 객체가 Arguments 객체인지 확인합니다.

1
2
3
4
(function(){ return _.isArguments(arguments); })(1, 2, 3);
// true
_.isArguments([1,2,3]);
// false

_.isFunction

_.isFunction 객체가 함수인지 확인합니다.

1
2
_.isFunction(alert);
// true

_.isString

_.isString(object) 객체가 문자열인지 확인합니다.

1
2
_.isString("marpple");
// true

_.isNumber

_.isNumber(object) 객체가 숫자인지 확인합니다.

1
2
_.isNumber(8.4 * 5);
// true

_.isDate

_.isDate(new Date()) 객체가 날짜 객체인지 확인합니다.

1
2
_.isDate(new Date());
// true

_.isRegExp

_.isRegExp(object) 객체가 정규식인지 확인합니다.

1
2
_.isRegExp(/marpple/);
// true

_.isError

_.isError(object) 객체가 에러 객체인지 확인합니다.

1
2
3
4
5
6
try {
throw new TypeError("Example");
} catch (o_O) {
_.isError(o_O);
}
// true

_.isArrayLike

_.isArrayLike 객체가 ArrayLike인지 확인합니다.

1
2
3
4
(function(){ return _.isArrayLike(arguments); })(1, 2, 3);
// true
_.isArrayLike({name: 'moe', age: 50});
// false

Function

_.memoize

_.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)를 지정하여 함수를 만듭니다. 옵션으로 함수의 인자를 받을 수 있습니다.

1
2
3
4
var func = function(greeting){ return greeting + ': ' + this.name };
func = _.bind(func, {name: 'moe'}, 'hi');
func();
// 'hi: moe'

Utility

_.identity

_.identity(value) 받은 값을 그대로 반환합니다.

1
2
3
var stooge = {name: 'moe'};
stooge === _.identity(stooge);
// true

_.constant

_.constant(value) 항상 받은 값을 반환하는 함수를 반환합니다.

1
2
3
var stooge = {name: 'moe'};
stooge === _.constant(stooge)();
// true

_.noop

_.noop() 항상 undefined를 반환합니다.

_.random

_.random(min, max) min값과 max값 사이의 임의의 정수 값을 반환합니다.

_.hi

_.hi(value) console.logvalue를 로그를 남긴 뒤 value를 반환합니다.

1
2
3
4
5
6
7
var stooge = _.hi({name: 'moe'}); // {name: 'moe'}
console.log(stooge); // {name: 'moe'}
_.go(stooge,
_.hi, // {name: 'moe'}
_.keys,
_.log) // ['name']

JSON Selector

_.sel

_.sel(object, selector)은 깊은 값을 찾아가기 위한 JSON Selector를 인자로 받습니다. JSON Selector는 깊은 값을 조회하기 위한 쿼리문입니다.

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
var users = [
{
id: 1,
name: 'BJ',
post_count: 3,
posts: [
{ id: 1, body: '하이', comments: [{ id: 3, body: '코멘트3' }] },
{ id: 2, body: '하이2', comments: [{ id: 1, body: '코멘트1' }, { id: 2, body: '코멘트2' }] },
{ id: 4, body: '하이4', comments: [{ id: 4, body: '코멘트4' }, { id: 5, body: '코멘트5' }] }
]
},
{
id: 2,
name: 'PJ',
post_count: 1,
posts: [
{ id: 3, body: '하이3', comments: [] }
]
}
];
// key로만 찾기
console.log(
_.sel(users, '0->name'), // BJ
_.sel(users, '1->name'), // PJ
_.sel(users, '0->post_count'), // 3
_.sel(users, '1->post_count'), // 1
_.sel(users, '0->posts->1->body') // 하이2
);
// 괄호로 내부적으로 find + predicate 실행하기
console.log(
_.sel(users, '(u=>u.id==1)->name'), // BJ
_.sel(users, '(u=>u.id==1)->posts->(p=>p.id==4)->body') // 하이4
);
// 동일 코드를 아래처럼 더 짧게 표현할 수 있습니다.
console.log(
_.sel(users, '($.id==1)->name'), // BJ
_.sel(users, '(#1)->posts->(#4)->body') // 하이4
);

()를 사용할 때 id로 비교하는 경우에는 #을 사용하는 방식이 성능이 가장 좋습니다. JSON Selector는 ()를 통해 find(predicate)를 작성할 수 있어 단순히 key들로 찾아가는 방법보다 유용합니다. JSON Selector의 ()는 함수이므로, id 비교외에 다른 조건도 얼마든지 만들 수 있습니다.

Mutable

_.set

_.set(object, selector, value)은 첫 번째 인자로 변경할 부모 객체를 받고, 두 번째 인자로 JSON Selector를 받아, 해당 부분의 값을 세 번째 인자로 받은 값으로 변경합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var user = {
id: 1,
name: 'BJ',
post_count: 3,
posts: [
{ id: 1, body: '하이', comments: [{ id: 3, body: '코멘트3' }] },
{ id: 2, body: '하이2', comments: [{ id: 1, body: '코멘트1' }, { id: 2, body: '코멘트2' }] },
{ id: 4, body: '하이4', comments: [{ id: 4, body: '코멘트4' }, { id: 5, body: '코멘트5' }] }
]
};
_.set(user, 'posts->(#4)->comments->(#4)->body', '코멘트4를 수정');
console.log( user.posts[2].comments[0] );
// {id: 4, body: "코멘트4를 수정"}

_.set의 마지막인자에 함수를 전달하면 더 다양한 방법으로 값 변경이 가능합니다.

1
2
3
4
5
_.set(user, 'posts', posts => _.reject(posts, function(post) {
return post.comments.length < 2;
}));
console.log( _.pluck(user.posts, 'body') );
// ["하이2", "하이4"]

_.unset

_.unset(object, selector)은 첫 번째 인자로 변경할 부모 객체를 받고, 두 번째 인자로 JSON Selector를 받아, 해당 부분의 key/value를 삭제합니다.

1
2
3
_.unset(user, 'posts->(#4)->comments->(#4)->body');
console.log( user.posts[2].comments[0] );
// {id: 4}

_.push

_.push(object, selector, value)는 첫 번째 인자로 변경할 부모 객체를 받고, 두 번째 인자로 JSON Selector를 받아, 해당 부분의 배열에 세 번째 인자로 받은 값을 더합니다.

1
2
3
_.push(user, 'posts->(#4)->comments', { id: 6, body: '코멘트6' });
console.log( _.last(user.posts[2].comments) );
// { id: 6, body: '코멘트6' }

_.pop

1
2
3
console.log( user.posts[1].comments.length ); // 2
_.pop(user, 'posts->(#2)->comments');
console.log( user.posts[1].comments.length ); // 1

_.shift

1
2
3
console.log( _.pluck(user.posts, 'body') ); // ["하이", "하이2", "하이4"]
_.shift(user, 'posts');
console.log( _.pluck(user.posts, 'body') ); // ["하이2", "하이4"]

_.unshift

1
2
3
_.unshift(user, 'posts->(#4)->comments', { id: 7, body: '코멘트7' });
console.log( _.first(user.posts[2].comments) );
// { id: 7, body: '코멘트7' }

_.extend2

1
2
3
_.extend2(user, 'posts->(#2)', { body: "내용 변경", body2: "내용 추가" });
console.log( user.posts[1] );
// {id: 2, body: "내용 변경", comments: Array(2), body2: "내용 추가"}

_.defaults2

1
2
3
4
5
6
7
console.log( user.posts[1] );
// {id: 2, body: "하이2", comments: Array(2)}
_.defaults2(user, 'posts->(#2)', { body: "내용 변경", body3: "내용 추가" });
console.log( user.posts[1] );
// {id: 2, body: "하이2", comments: Array(2), body2: "내용 추가"}

_.remove2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var user = {
id: 1,
name: 'BJ',
post_count: 3,
posts: [
{ id: 1, body: '하이', comments: [{ id: 3, body: '코멘트3' }] },
{ id: 2, body: '하이2', comments: [{ id: 1, body: '코멘트1' }, { id: 2, body: '코멘트2' }] },
{ id: 4, body: '하이4', comments: [{ id: 4, body: '코멘트4' }, { id: 5, body: '코멘트5' }] }
]
}
_.remove2(user, 'posts->(#2)->comments', user.posts[1].comments[0]);
console.log(user.posts[1].comments);
// [{ id: 2, body: '코멘트2' }]

Immutable

Mutable 함수들 앞에 _.im를 붙이면 깊은 값을 불변적으로 다룰 수 있습니다. 예를 들어 _.im.set은 첫 번째 인자로 변경할 부모 객체를 받고, 두 번째 인자로 JSON Selector를 받아, 해당 부분의 값을 세 번째 인자로 받은 값으로 변경합니다. 단 기존의 값은 변경하지 않고 안쪽 값이 변경된 새로운 부모 객체를 리턴합니다.

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
var user = {
id: 1,
name: 'BJ',
post_count: 3,
posts: [
{ id: 1, body: '하이', comments: [{ id: 3, body: '코멘트3' }] },
{ id: 2, body: '하이2', comments: [{ id: 1, body: '코멘트1' }, { id: 2, body: '코멘트2' }] },
{ id: 4, body: '하이4', comments: [{ id: 4, body: '코멘트4' }, { id: 5, body: '코멘트5' }] }
]
};
_.go(
_.im.set(user, 'posts -> (#4) -> comments -> (#4) -> body', '코멘트4를 새롭게 수정'),
function(user2) {
console.log(
user == user2, // false
user.posts[2].comments[0].body, // 코멘트4
user2.posts[2].comments[0].body, // 코멘트4를 새롭게 수정
user.posts == user2.posts, // false
user.posts[0] == user2.posts[0], // true 기존 값 공유
user.posts[1] == user2.posts[1], // true 기존 값 공유
user.posts[2] == user2.posts[2], // false 부모 라인이므로 새로운 값
user.posts[2].comments[0] == user2.posts[2].comments[0], // false 새로운 값
user.posts[2].comments[1] == user2.posts[2].comments[1] // true 기존 값 공유
)
});
var users = [
{
id: 1,
name: 'BJ',
post_count: 3,
posts: [
{ id: 1, body: '하이', comments: [{ id: 3, body: '코멘트3' }] },
{ id: 2, body: '하이2', comments: [{ id: 1, body: '코멘트1' }, { id: 2, body: '코멘트2' }] },
{ id: 4, body: '하이4', comments: [{ id: 4, body: '코멘트4' }, { id: 5, body: '코멘트5' }] }
]
},
{
id: 2,
name: 'PJ',
post_count: 1,
posts: [
{ id: 3, body: '하이3', comments: [] }
]
}
];
_.go(_.im.remove2(users, '(#2)->posts->(#3)'),
function(users2) {
console.log(users2[1].posts); // []
console.log(users[1].posts); // [{ id: 3, body: '하이3', comments: [] }]
});
_.go(
_.im.set(users, '(#1)->posts', function(posts) {
return _.pluck(posts, 'body');
}),
function(users2) {
console.log(users == users2); // false
console.log(users2[0].posts); // ["하이", ""하이2", "하이4"]
console.log(users[0].posts[0]); // {id: 1, body: "하이", comments: Array(1)}
});

위와 같이 깊은 값을 불변적으로 다룰 수 있습니다. 이때 변경이 되지 않은 모든 값은 새로 만들지 않고 공유하는 영속성을 가지고 있습니다. Immutable이 지원되는 함수들은 다음과 같습니다.

  • _.im.set
  • _.im.unset
  • _.im.push
  • _.im.pop
  • _.im.shift
  • _.im.unshift
  • _.im.extend
  • _.im.extend2
  • _.im.defaults
  • _.im.defaults2
  • _.im.remove2

Box

Box는 모든 Mutable 함수와 Immutable 함수를 OOP 스타일로 다루는 함수입니다. _.box 함수로 값을 모아두는 인스턴스를 만든 후 메서드를 실행하는 식으로 사용합니다.

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
var box1 = _.box({
users: [
{
id: 1,
name: 'BJ',
posts: [
{ id: 1, body: '하이', comments: [{ id: 3, body: '코멘트3' }] },
{ id: 2, body: '하이2', comments: [{ id: 1, body: '코멘트1' }, { id: 2, body: '코멘트2' }] },
{ id: 4, body: '하이4', comments: [{ id: 4, body: '코멘트4' }, { id: 5, body: '코멘트5' }] }
]
},
{
id: 2,
name: 'PJ',
posts: [
{ id: 3, body: '하이3', comments: [{ id: 6, body: '코멘트6' }] }
]
}
]
});
console.log( box1.sel('users->(#1)->name') ); // BJ
box1.set('users->(#1)->name', 'BJ2');
console.log( box1.sel('users->(#1)->name') ); // BJ2
_.go(box1.im.set('users->(#1)->name', 'BJ3'),
function(box2) {
console.log( box2.sel('users->(#1)->name') ); // BJ3
console.log( box1.sel('users->(#1)->name') ); // BJ2
});

Notification

  • _.noti.on
  • _.noti.off
  • _.noti.emit
  • _.noti.emitAll

이벤트를 듣고 이벤트를 울리는 함수세트입니다. 부수 효과를 최소화할 수 있도록 몇 가지 기능을 제공합니다.

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
_.noti.on("event_name1", "listener_name1", function(a, b, c) {
console.log(a, b, c);
});
_.noti.on("event_name1", "listener_name2", function() {
console.log(_.reduce(arguments, (a, b) => a + b));
});
_.noti.on("event_name1", "listener_name3", function() {
console.log(_.reduce(arguments, (a, b) => a * b));
});
_.noti.emitAll("event_name1", [1, 2, 3, 4]);
// 1 2 3 4
// 10
// 24
_.noti.emit("event_name1", "listener_name2", [1, 2, 3, 4]);
// 10
_.noti.emit("event_name1", ["listener_name2", "listener_name3"], [1, 2, 3, 4]);
// 10
// 24
_.noti.emit("event_name1", function(listener_names) {
return _.initial(listener_names); // 여기서 리턴 되는 리스너들만 실행
}, [1, 2, 3, 4]);
// 1 2 3
// 10
_.noti.off('event_name1', 'listener_name2'); // event_name1 중 `listener_name2`만 삭제
_.noti.emitAll("event_name1", [1, 2, 3, 4]);
// 1 2 3
// 24
_.noti.off('event_name1'); // event_name1으로 등록된 모든 리스너 삭제
_.noti.emitAll("event_name1", [1, 2, 3, 4]);
// 아무일 없음

Template

Partial.js는 함수 스타일의 템플릿 엔진으로 함수 실행, 코드 실행, 인자 선언, Jade 스타일 문법 지원, 일반 HTML 문법 지원, 비동기 제어 등의 기능을 지원합니다.

Laziness

Partial.js의 L을 이용하면, 파이프라인 내부에서 함수들의 실행 순서를 재배치하여 적절하게 평가를 지연합니다.