오늘은 underscore.js 라이브러리의 일부를 직접 구현해보는 시간을 가졌다.
underscore.js란 기본 JavaScript 객체들을 확장하지 않고, 함수형 프로그래밍을 지원할 수 있는 100가지 이상의 함수를 가진 유용한 JavaScript 라이브러리를 말한다.
그렇다면 지금부터 오늘 직접 구현해본 라이브러리를 설명해보겠다.
1) ._take
배열의 처음 n개의 element를 담은 새로운 배열을 리턴한다.
_.take = function (arr, n) { if(n === undefined || n <= 0) { // n이 undefined이거나 음수인 경우, 빈 배열 리턴 return []; } if(arr.length < n) { // n이 배열의 길이를 벗어날 경우, 전체 배열을 shallow copy한 새로운 배열을 리턴 return arr; } let result = []; for(let i = 0; i < n; i++) { //arr의 1부터 n개의 element를 담는다. result.push(arr[i]); } return result; };
2) ._drop
처음 n개의 element를 제외한 새로운 배열을 리턴한다.
_.drop = function (arr, n) { if(n === undefined || n <= 0) { // n이 undefined이거나 음수인 경우, 전체 배열을 shallow copy한 새로운 배열을 리턴 return arr; } if(arr.length < n) { // n이 배열의 길이를 벗어날 경우, 빈 배열을 리턴 return []; } let result = []; for(let i = n; i < arr.length; i++) { //arr의 n부터 element를 담는다. result.push(arr[i]); } return result; };
3) ._last
배열의 마지막 n개의 element를 담은 새로운 배열을 리턴한다.
_.last = function (arr, n) { if(n === undefined || n < 0) { // n이 undefined이거나 음수인 경우, 배열의 마지막 요소만을 담은 배열을 리턴 return [arr[arr.length-1]]; } else if(arr.length < n) { // n이 배열의 길이를 벗어날 경우, 전체 배열을 shallow copy한 새로운 배열을 리턴 return arr; } else if(n === 0) { return []; } let result = []; for(let i = arr.length-n; i < arr.length; i++) { //arr.length-n 인덱스부터 새로운 배열에 추가 result.push(arr[i]); } return result; };
4)._each
collection의 각 데이터에 반복적인 작업을 수행한다.
_.each = function (collection, iteratee) { //collection(배열 혹은 객체)과 함수 iteratee(반복되는 작업)를 인자로 받는다. if(Array.isArray(collection)) { for(let i = 0; i < collection.length; i++) { //collection의 데이터를 순회하면서 iteratee(collection[i],i,collection); // iteratee에 각 데이터를 인자로 전달하여 실행한다. } } else { for(let key in collection) { iteratee(collection[key], key, collection); } } };
5)._filter
test 함수를 통과하는 모든 요소를 담은 새로운 배열을 리턴한다.
_.filter = function (arr, test) { let result = []; _.each(arr, function (el) { //각 요소에 반복 적용한다. if (test(el)) { //test(element)의 결과(return 값)가 true라면 result.push(el); //새로운 배열에 추가한다. } }); return result; };
6)._reject
test 함수를 통과하지 않는 모든 요소를 담은 새로운 배열을 리턴한다.
_.reject = function (arr, test) { let result = []; _.each(arr, function (el) { //각 요소에 반복 적용한다. if(!test(el)) { //test(element)의 결과(return 값)가 false라면 result.push(el); //새로운 배열에 추가한다. } }); return result; };
7)._uniq
주어진 배열의 요소가 중복되지 않도록 새로운 배열을 리턴한다.
_.uniq = function (arr) { let result = []; _.each(arr, function(el) { //각 요소에 반복 적용한다. for(let i = 0; i < arr.length; i++) { if(result[i] === el) { //중복되는 요소가 발견되면 return ; //배열에 추가하지않고 return 한다. } } result.push(el); //중복되는 요소가 발견되지 않으면 배열에 요소를 추가한다. }) return result; };
8)._map
iteratee(반복되는 작업)를 배열의 각 요소에 적용한 결과를 담은 새로운 배열을 리턴한다.
_.map = function (arr, iteratee) { let newArr = []; _.each(arr, function(el) { //각 요소에 반복 적용한다. newArr.push(iteratee(el)); //iteratee를 적용한 결과를 배열에 추가한다. }) return newArr; };
9)._pluck
객체 또는 배열을 요소로 갖는 배열과 각 요소에서 찾고자 하는 key 또는 index를 입력받아 각 요소의 해당 값 또는 요소만을 추출하여 새로운 배열에 저장하여 리턴한다.
_.pluck = function (arr, keyOrIdx) { let result = []; _.map(arr, function(el) { //각 요소에 반복 적용한다. result.push(el[keyOrIdx]); //각 요소의 해당 값(요소)를 배열에 추가한다. }) return result; };
10)._reduce
배열을 순회하며 각 요소에 iteratee 함수를 적용하고, 그 결과값을 계속해서 누적하여 그 결과값을 리턴한다.
_.reduce = function (arr, iteratee, initVal) { let acc = initVal; _.each(arr, function (ele, idx, arr) { //각 요소에 반복 적용한다. if(acc === undefined) { //초기값이 주어지지 않았다면 배열의 첫번째 요소 할당 acc = arr[0]; } else{ acc = iteratee(acc, ele, idx, arr); //각 요소를 iteratee 함수에 적용하고 그 결과값을 계속해서 누적한다. } }); return acc; };
오늘은 라이브러리를 직접 구현해보면서 자바스크립트의 기본 문법에 능숙해지는 시간을 가졌다. 내일도 더 추가적인 라이브러리를 공부해보자.
오늘은 여기까지 :)