본문 바로가기

Back-end/library

javascript underscore 언더스코어 정리

언더스코어란?

코딩을 도와주는 자바스크립트 라이브러리로 매우 작은 용량에 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"};