언더스코어란?
코딩을 도와주는 자바스크립트 라이브러리로 매우 작은 용량에 80여가지의 function을 제공.
언더스코어 함수중에는 ES5, ES6를 거쳐 내장함수로 이미 지원하는 함수들이 있으므로 이미
브라우저 내장함수로 지원하고있다면 성능을 위해 내장함수를 이용하자.
용어설명
Context
bind로 묶어준다.
iteratee
반복처리 시키는 내용이다.
Context와 iteratee의 구분
// _.each(list, iteratee, [context])
_.each([1, 2, 3], alert);
=> alerts each number in turn...
_.each({one: 1, two: 2, three: 3}, alert);
=> alerts each number value in turn...
context를 지정하지 않았을 경우 list의 내용들이 iteratee를 통해 처리된다
_.each([1, 2, 3], function(num) {
// In here, "this" refers to the same Array as "someOtherArray"
alert( this[num] ); // num is the value from the array being iterated
// so this[num] gets the item at the "num" index of
// someOtherArray.
}, someOtherArray);
context가 있을 경우 this로 바인딩한다.
Collection Functions (Arrays or Objects)
each
사용가능한경우 ES5 네이티브인 forEach를 사용하자.
각 요소에 iteratee를 적용한 결과를 리턴한다.
//_.each(list, iteratee, [context])
_.each([1, 2, 3], alert);
=> alerts each number in turn...
_.each({one: 1, two: 2, three: 3}, alert);
=> alerts each number value in turn...
map
each와 비슷하지만 새로운 콜렉션을 만듬
//_.map(list, iteratee, [context])
_.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
입력받은 리스트로부터 하나의 결과를 작성함
memo는 reduction의 초기값 각각의 단계는 반드시 리턴값을 가져야하고
해당 리턴값이 재귀함수형식으로 계속 반복싱행되어야 한다.
사용가능한경우 ES5 reduce를 사용
//_.reduce(list, iteratee, [memo], [context])
var sum = _.reduce([1, 2, 3],function(memo, num){
return memo + num;
}, 0);
=> 6
reduceRight
reduce를 오른쪽부터 이어붙임(right-associative)
사용가능한경우 es5 reuce를 이용
//_.reduceRight(list, iteratee, memo, [context])
var list = [[0, 1], [2, 3], [4, 5]];
var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []);
=> [4, 5, 2, 3, 0, 1]
find
iteratee의 반환값이 true인 첫번째 값을 반환
//_.reduceRight(list, iteratee, memo, [context])
var even = _.find([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
=> 2
filter
find와는 다르게 true인 값을 리스트로 반환
//_.filter(list, predicate, [context])
var evens = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
=> [2, 4, 6]
where
list의 각 value에서
리스트에서 key-value값이 맞는 모든 properties를 반환
//_.where(list, properties)
_.where(listOfPlays, {author: "Shakespeare", year: 1611});
=> [{title: "Cymbeline", author: "Shakespeare", year: 1611},
{title: "The Tempest", author: "Shakespeare", year: 1611}]
findWhere
//_.findWhere(list, properties)
where와 비슷하지만 처음값 하나만을 리턴한다.
reject
true면 포함 false면 뺌
되도록 ES5 filter를 쓰도록하자.
//_.reject(list, predicate, [context])
var odds = _.reject([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
=> [1, 3, 5]
every
list내 모든게 참이여야 true를 반환
되도록 ES5 filter를 쓰도록하자.
//_.every(list, [predicate], [context])
_.every([2, 4, 5], function(num) { return num % 2 == 0; });
=> false
some
하나라도 참이면 true!
//_.some(list, [predicate], [context])
_.some([null, 0, 'yes', false]);
=> true
contains
lis에 해당 value값이 있으면 참 fromIndex를 넣을경우 해당 index에 값이 있어야 참
//_.contains(list, value, [fromIndex])
_.contains([1, 2, 3], 3);
=> true
invoke
list에서 methodName을 정의하면 해당 method를 이용 return값 반환
//_.invoke(list, methodName, *arguments)
_.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
=> [[1, 5, 7], [1, 2, 3]]
pluck
list에 propery 이름이 동일한 값을 받아 새로운 리스트를 만든다
//_.pluck(list, propertyName)
var stooges = [{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}];
_.pluck(stooges, 'name');
=> ["moe", "larry", "curly"]
max
최대값 반환
//_.max(list, [iteratee], [context])
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], [context])
sortBy
sorting 용
//_.sortBy(list, iteratee, [context])
_.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
리턴값이 같은것끼리 array로 묶음
//_.groupBy(list, iteratee, [context])
_.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
배열들을 index값을 기준으로 mapping
//_.indexBy(list, iteratee, [context])
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
iteratee의 반환값의 개수를 반환
//_.countBy(list, iteratee, [context])
_.countBy([1, 2, 3, 4, 5], function(num) {
return num % 2 == 0 ? 'even': 'odd';
});
=> {odd: 3, even: 2}
suuffle
섞어서 copy list 반환
//_.shuffle(list)
_.shuffle([1, 2, 3, 4, 5, 6]);
=> [4, 1, 6, 3, 5, 2]
sample
랜덤하게 뽑는다.
//_.sample(list, [n])
_.sample([1, 2, 3, 4, 5, 6]);
=> 4
_.sample([1, 2, 3, 4, 5, 6], 3);
=> [1, 6, 2]
toArray
argument 들을 배열로 리턴
//_.toArray(list)
(function(){ return _.toArray(arguments).slice(1); })(1, 2, 3, 4);
=> [2, 3, 4]
list
배열 개수 반환
//_.size(list)
_.size({one: 1, two: 2, three: 3});
=> 3
partition
array를 두 그룹으로 나눈다 그 후 만족하는 것과 만족하지 않는것을 각각
어레이로 묶는다.
//_.partition(array, predicate)
_.partition([0, 1, 2, 3, 4, 5], isOdd);
=> [[1, 3, 5], [0, 2, 4]]
Array Functions
first
return first elelment
n이 있으면 앞에서 n번째
//_.initial(array, [n])
_.first([5, 4, 3, 2, 1]);
=> 5
initial
뒤에서 n번째
//_.last(array, [n])
_.last([5, 4, 3, 2, 1]);
=> 1
last
first와 동일하나 뒤에서부터
//_.last(array, [n])
_.last([5, 4, 3, 2, 1]);
=> 1
rest
index 앞까지 스킵하고 나머지 리턴.
//_.rest(array, [index])
_.rest([5, 4, 3, 2, 1]);
=> [4, 3, 2, 1]
compact
false,null,0,””빼고 다 반환
//_.compact(array)
_.compact([0, 1, false, 2, '', 3]);
=> [1, 2, 3]
flatter
nesting을 어느 depth던 다 제거한다. shallow를 true로 주면 single level만
제거한다
//_.flatten(array, [shallow])
_.flatten([1, [2], [3, [[4]]]]);
=> [1, 2, 3, 4];
_.flatten([1, [2], [3, [[4]]]], true);
=> [1, 2, 3, [[4]]];
without
value값을 제외한 나머지값을 리턴
//_.without(array, *values)
_.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
=> [2, 3, 4]
union
전달 된 모든 배열의 각 개별 요소의 집합을 포함하는 배열을 제공한다.
//_.union(*arrays)
_.union([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2, 3, 101, 10]
intersection
교집합
//_.intersection(*arrays)
_.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2]
difference
차집합
//_.difference(array, *others)
_.difference([1, 2, 3, 4, 5], [5, 2, 10]);
=> [1, 3, 4]
uniq
중복이 없도록 한 배열을 제공한다. 배열이 이미 정렬되어있으면,
빠른 알고리즘을 사용할 수있는 옵션이있다.
//_.uniq(array, [isSorted], [iteratee])
_.uniq([1, 2, 1, 4, 1, 3]);
=> [1, 2, 4, 3]
zip
서로 상응하는 값끼리 묶어준다
//_.zip(*arrays)
_.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]);
=> [["moe", 30, true], ["larry", 40, false], ["curly", 50, false]]
unzip
zip의 반대개념
//_.unzip(array)
_.unzip([["moe", 30, true], ["larry", 40, false], ["curly", 50, false]]);
=> [['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]]
object
obj를 array로 변환해준다 단일값이나 key,value 쌍으로 가능
//_.object(list, [values])
_.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
몇번째 value인지 sorting 되어있다면 isSorted 에 true를 주어 더욱 빠르게 검색가능
//_.indexOf(array, value, [isSorted])
_.indexOf([1, 2, 3], 2);
=> 1
lastIndexOf
indexOf의 reverse 버전
//_.lastIndexOf(array, value, [fromIndex])
_.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
=> 4
sortedIndex
sorting 되어있는 값을 기준으로 몇번째 인덱스에 넣을 수 있는지 반환
//_.sortedIndex(list, value, [iteratee], [context])
_.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
indexof와 비슷하나 predicate(true or flase)에서 true된 값을 기준으로 한다
//_.findIndex(array, predicate, [context])
_.findIndex([4, 6, 8, 12], isPrime);
=> -1 // not found
_.findIndex([4, 6, 7, 12], isPrime);
=> 2
FindLastIndex
findIndex reverse version
//_.findLastIndex(array, predicate, [context])
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, {
name: 'Ted'
});
=> 3
range
범위
//_.range([start], stop, [step])
_.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);
=> []
Functional function
bind
바인딩
//_.bind(function, object, *arguments)
var func = function(greeting){ return greeting + ': ' + this.name };
func = _.bind(func, {name: 'moe'}, 'hi');
func();
=> 'hi: moe'
bindAll
//_.bindAll(object, *methodNames)
var buttonView = {
label : 'underscore',
onClick: function(){ alert('clicked: ' + this.label); },
onHover: function(){ console.log('hovering: ' + this.label); }
};
_.bindAll(buttonView, 'onClick', 'onHover');
// When the button is clicked, this.label will have the correct value.
jQuery('#underscore_button').on('click', buttonView.onClick);
partial
인자를 하나씩 넣을 수 있다.
//_.partial(function, *arguments)
var subtract = function(a, b) { return b - a; };
//subtract의 인자 2개
sub5 = _.partial(subtract, 5);
//subtract의 첫 인자에 5를 셋팅한 값을 sub5에 넘김
sub5(20);
//sub5 = subtract(5,argument)
=> 15
// Using a placeholder
subFrom20 = _.partial(subtract, _, 20);
//_로 막아놓기 가능
subFrom20(5);
=> 15
memoize
결과를 저장하는 것으로, 고비용의 함수를 memoize 화한다.
//_.memoize(function, [hashFunction])
var fibonacci = _.memoize(function(n) {
return n < 2 ? n: fibonacci(n - 1) + fibonacci(n - 2);
});
delay
시간만큼 딜레이 후 실행시킴
//_.delay(function, wait, *arguments)
var log = _.bind(console.log, console);
_.delay(log, 1000, 'logged later');
=> 'logged later' // Appears after one second.
defer
call stack의 내용이 전부 처리되면 실행시킨다
//_.defer(function, *arguments)
_.defer(function(){ alert('deferred'); });
// Returns from the function before the alert runs.
throttled
호출되면 지정된 시간 내에 최대 1 번만 트리거되는 함수를 돌려 준다.
//_.throttle(function, wait, [options])
var throttled = _.throttle(updatePosition, 100);
$(window).scroll(throttled);
debounce
연속 호출되는 한 트리거되지 않는 함수를 돌려준다.
예를들어 함수가 wiat만큼 기다리는동안 immediate의 return값을
받을경우 혹은 연속된 호출을 받을경우 호출이 시작된 시점부터 다시
카운팅 후 실행되게 된다.
//_.debounce(function, wait, [immediate])
var lazyLayout = _.debounce(calculateLayout, 300);
$(window).resize(lazyLayout);
once
딱 한번만 실행
//_.once(function)
var initialize = _.once(createApplication);
initialize();
initialize();
// Application is only created once.
after
n번 호출된 이후에 실행한다.
//_.after(count, function)
var renderNotes = _.after(notes.length, render);
_.each(notes, function(note) {
note.asyncSave({success: renderNotes});
});
// renderNotes is run once, after all notes have saved.
before
횟수제한
//_.before(count, function)
var monthlyMeeting = _.before(3, askForRaise);
monthlyMeeting();
monthlyMeeting();
monthlyMeeting();
// the result of any subsequent calls is the same as the second call
wrap
wrap을 씌워준다.
//.wrap(function, wrapper)
var hello = function(name) { return "hello: " + name; };
hello = _.wrap(hello, function(func) {
return "before, " + func("moe") + ", after";
});
hello();
=> 'before, hello: moe, after'
negate
predicate를 0 혹은 1로 반환하는 것같다.
//_.negate(predicate)
var isFalsy = _.negate(Boolean);
_.find([-2, -1, 0, 1, 2], isFalsy);
=> 0
compose
함수 목록에서 각각의 함수가 거기에 계속되는 함수의 반환 값을 인수에 취하는 합성 함수를 돌려 준다.
f(), g(), and h() produces f(g(h())).
//_.compose(*functions)
var greet = function(name){ return "hi: " + name; };
var exclaim = function(statement){ return statement.toUpperCase() + "!"; };
var welcome = _.compose(greet, exclaim);
welcome('moe');
=> hi! moe
Object Functions
keys
obj의 key 반환
//_.keys(object)
_.keys({one: 1, two: 2, three: 3});
=> ["one", "two", "three"]
allKeys
obj의 모든 inherited properties 출력
//_.allKeys(object)
function Stooge(name) {
this.name = name;
}
Stooge.prototype.silly = true;
_.allKeys(new Stooge("Moe"));
=> ["name", "silly"]
values
value 반환
//_.values(object)
_.values({one: 1, two: 2, three: 3});
=> [1, 2, 3]
mapObject
예제를 보자
//_.mapObject(object, iteratee, [context])
_.mapObject({start: 5, end: 12}, function(val, key) {
return val + 5;
});
paris
obj to list
//_.pairs(object)
_.pairs({one: 1, two: 2, three: 3});
=> [["one", 1], ["two", 2], ["three", 3]]
invert
obj의 key값과 value값을 바꿔준다.
//t_.invert(object)
_.invert({Moe: "Moses", Larry: "Louis", Curly: "Jerome"});
=> {Moses: "Moe", Louis: "Larry", Jerome: "Curly"};