Underscore.js
:
map,filter,invoke등 100여개의 유용한 함수들을 제공하는 JavaScript 라이브러리
Underscore.js
: 데이터(data)/자료의 모음, 대표적으로 배열과 객체
우리는 주로 collection을 가지고 collection 각 데이터에 반복 작업(iteration)을 한다.
JavaScript에서는 이러한 iteration을 위해 반복문과 반복을 위한 내장 메소드를 제공한다.
for, for...of, for...in, whilearr.map, arr.filterfor(let i = 0; i < 3; i++) {
console.log(i); // 0 // 1 // 2
}
이때, console.log(i); 처럼 반복되는 작업을 iteratee라고 부른다.
Underscore.js 라이브러리에서 제공하는 함수 중, collection을 다루는 몇 가지 함수를 직접 구현해보자.
_.slice()_.slice(arr, start, end) : 배열의 start부터 end 전까지의 요소를 얕게 복사(shallow copy)해 새로운 배열로 만들어 반환하는 함수
_.slice = function(arr, start, end) {
let _start = start || 0;
let _end = end;
if(start < 0) _start = Math.max(0, arr.length + start);
if(end < 0) _end = Math.max(0, arr.length + end);
if(_end === undefined || _end > arr.length) _end = arr.length;
let result = [];
for(let i = _start; i < _end; i++) {
result.push(arr[i]);
}
return result;
}
_.slice = function(arr, start, end) {
// start를 입력하지 않았을 경우(undefined), _start는 0부터 시작한다.
let _start = start || 0;
let _end = end;
// 만약 index에 -1을 넣었을 경우, arr.length - 1을 반환한다.
// 만약 배열의 길이를 초과하는 index를 넣을 경우, 0을 반환한다.
if(start < 0) {
_start = Math.max(0, arr.length + start);
}
if(end < 0) {
_end = Math.max(0, arr.length + end);
}
// end를 입력하지 않았을 경우(undefined), _end는 배열의 끝까지이다.
// end가 배열의 범위를 벗어날 경우, _end는 배열의 끝까지이다.
if(_end === undefined || _end > arr.length) {
_end = arr.length;
}
let result = []; // 새로운 배열을 만들어 반환한다.
for(let i = _start; i < _end; i++) {
result.push(arr[i]);
}
return result;
}
_.take()_.take(arr, n) : 배열의 처음 n개의 요소를 담은 새로운 배열을 반환하는 함수
n이 undefined이거나 음수인 경우, 빈 배열을 리턴한다.n이 배열의 길이를 벗어난 경우, 전체 배열 얕게 복사한 새로운 배열을 리턴한다._.take = function(arr, n) {
let result = [];
if(n === undefined || n < 0) n = 0;
else if(n > arr.length) n = arr.length;
for(let i = 0; i < n; i++) {
result.push(arr[i]);
}
return result;
};
_.drop()_.drop(arr, n) : _.take()와 정반대로 배열의 처음 n개의 요소를 제외한 새로운 배열을 반환하는 함수
n이 undefined거나 음수인 경우, 전체 배열을 얕게 복사한 새로운 배열을 리턴한다.n이 배열의 길이를 벗어날 경우, 빈 배열을 리턴한다._.drop = function(arr, n) {
let result = [];
if(n === undefined || n < 0) n = 0;
else if(n > arr.length) n = arr.length;
for(let i = n; i < arr.length; i++) {
result.push(arr[i]);
}
return result;
};
_.last()_.last(arr, n) : 배열의 마지막 n개의 요소를 담은 새로운 배열을 반환하는 함수
n이 undefined거나 음수인 경우, 배열의 마지막 요소만 담은 배열을 리턴한다.n이 배열의 길이를 벗어날 경우, 전체 배열을 얕게 복사한 새로운 배열을 리턴한다._.drop() 함수를 활용한다._.last = function(arr, n) {
if(n === undefined || n < 0) n = 1;
return _.drop(arr, arr.length - n);
};
forEach()
arr.forEach(callback): 배열을 순회하며 배열의 각 요소에 주어진 함수를 실행하는 메소드
callback(currentValue, index, array)
forEach()메소드의 매개변수인 콜백 함수는 다음 세 가지 매개변수와 함께 호출된다.
currentValue: 요소 값index: 요소 인덱스array: 순회 중인 배열
_.each()_.each(collection, iteratee) : collection을 순회하며 collection의 각 데이터에 iteratee 함수를 실행하는 함수
element/value), 접근자(index/key), collection(배열/객체)을 다룰 수 있어야 한다.el idx collection)value key collection)_.each = function(collection, iteratee) {
// collection이 배열일 때
if(Array.isArray(collection)) {
for(let i = 0; i < collection.length; i++) {
iteratee(collection[i], i, collection);
}
// collection이 객체일 때
} else {
for(let key in collection) {
iteratee(collection[key], key, collection);
}
}
};
indexOf()
arr.indexOf(searchelement): 배열에서 지정된 요소를 찾을 수 있는 첫 번째 인덱스를 반환하고 존재하지 않으면 -1을 반환하는 메소드
_.indexOf()_.indexOf(arr, target) : target이 arr의 요소인 경우, 배열에서의 index를 반환하고, 그렇지 않으면 -1을 반환하는 함수
target이 중복해서 존재하는 경우, 가장 낮은 index를 반환한다._.each() 함수를 활용해 배열을 순회한다._.indexOf = function(arr, target) {
let result = -1;
_.each(arr, function(el, idx) {
if(target === el && result === -1) { // 가장 낮은 index를 반환하기 위한 장치
result = idx;
}
});
return result;
};
filter()
arr.filter(callback): 주어진 함수의 테스트를 통과하는 모든 요소를 모아 새로운 배열로 반환하는 메소드
callback(element, index, array)
filter()메소드의 매개변수인 콜백 함수는 다음 세 가지 매개변수와 함께 호출된다.
element: 요소값index: 요소 인덱스array: 순회되는 배열 객체
_.filter()_.filter(arr, test) : test 함수를 통과하는 모든 요소를 담은 새로운 배열을 반환하는 함수
test 함수의 결과값이 truthy일 경우 통과이다.test 함수는 각 요소에 반복 적용된다._.filter = function(arr, test) {
let result = [];
_.each(arr, function(el, idx, collection) {
if(test(el, idx, collection)) {
result.push(el);
}
});
return result;
};
_.reject()_.reject(arr, test) : _.filter()와 정반대로 test 함수를 통과하지 않는 모든 요소를 담은 새로운 배열을 반환하는 함수
_.reject = function(arr, test) {
let result = [];
_.each(arr, function(el, idx, collection) {
if(!test(el, idx, collection)) { // 조건문에 !만 추가
result.push(el);
}
});
return result;
};
_.uniq()_.uniq(arr) : 주어진 배열의 요소가 중복되지 않는 새로운 배열을 반환하는 함수
===)을 사용한다._.uniq = function(arr) {
let result = [];
_.each(arr, function(el, idx, collection) {
// result 배열에 el이 없으면, 추가한다.
if(_.indexOf(result, el) === -1) {
result.push(el);
}
});
return result;
};
map()
arr.map(callback): 배열 내의 각각의 요소에 주어진 함수를 실행한 결과를 모아 새로운 배열을 반환하는 메소드
callback(currentValue, index, array)
map()메소드의 매개변수인 콜백 함수는 다음 세 가지 매개변수와 함께 호출된다.
currentValue: 요소 값index: 요소 인덱스array: 순회 중인 배열
_.map()_.map(arr, iteratee) : 배열의 각 요소에 iteratee 함수를 적용한 결과를 담은 새로운 배열을 반환하는 메소드
_.map = function(arr, iteratee) {
let result = [];
_.each(arr, function(el, index, collection) {
result.push(iteratee(el, index, collection));
});
return result;
};
_.pluck()_.pluck(arr, keyOrIdx) : 매개변수로 ① 객체 또는 배열을 요소로 갖는 배열과 ② 각 요소에서 찾고자 하는 key/index를 입력 받아,
각 요소의 특정 요소/값만을 추출해 새로운 배열로 반환하는 함수
key/index가 없는 요소의 경우, 추출 결과는 undefined이다._.map() 함수를 활용한다. let result = []; // [[1, 2, 3], [4, 5, 6]]
_.map(arr, function(el) { // el = [1, 2, 3]
result.push(el[keyOrIdx]);
});
return result;
reduce()
arr.reduce(callback, initialValue): 배열의 각 요소에 대해 주어진 리듀서(reducer) 함수를 실행하고, 하나의 결과값을 반환하는 메소드
callback(acc, cur, idx, arr)
reduce()메소드의 매개변수인 콜백 함수는 다음 네 가지 매개변수와 함께 호출된다.
accumulator: 누적값currentValue: 현재 요소currentIndex: 현재 요소의 인덱스array: 순회 중인 배열
initialValue
- 최초 호출에서 첫 번째 인수(
acc)에 제공하는 값- 초기값을 제공하지 않으면 배열의 첫 번째 요소를 사용한다.
_.reduce()_.reduce(arr, iteratee, initVal) : 배열을 순회하며 각 요소에 iteratee 함수를 적용하여 그 결과값을 계속해서 누적하고, 최종적으로 누적된 결과값을 리턴하는 함수
_.reduce = function (arr, iteratee, initVal) {
let acc = initVal; // acc(누적값) = initVal(초기값)
// 이때 initVal은 값 또는 undefined
_.each(arr, function(el, idx, collection) {
// 초기값이 없는 경우, 배열의 arr[0]을 초기값으로 설정해준다.
if(acc === undefined) {
acc = arr[0];
// 초기값이 있는 경우, 배열을 순회하며 iteratee 함수를 실행하고, 결과값을 acc에 재할당한다.
} else {
acc = iteratee(acc, el, idx, collection);
}
});
return acc;
};