제로하우스
[JavaScript] Underbar 라이브러리 구현하기 본문
배열, 객체를 다루는
Underbar
라이브러리를 구현해본다.
Underbar의 모티브가 되는 라이브러리는 Underscore.js, Lodash 등이 있다.
_.identity
_.identity
는 전달인자가 무엇이든 그대로 리턴한다. 이 함수는 underbar의 기능 구현 및 테스트를 위해 재사용되는 함수이다.
_.identity = function (val) {
return val
};
_.slice
_.slice
는 배열의 start 인덱스부터 end 인덱스 이전까지의 요소를 shallow copy하여 새로운 배열을 리턴한다.
_.slice = function (arr, start, end) {
let _start = start || 0,
_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;
};
_.take
_.take
는 배열의 처음 n개의 요소를 담은 새로운 배열을 리턴한다. n이 undefined이거나 음수인 경우 빈 배열을 리턴하며, n이 배열의 길이를 초과할 경우에는 전체 배열을 shallow copy한 새로운 배열을 리턴한다.
_.take = function (arr, n) {
if (n === undefined || n < 0) {
return []
}
else if (n >= arr.length) {
let result = arr
return result
}
else {
let result = []
for (let i = 0; i < n; i++) {
result.push(arr[i])
}
return result
}
};
_.drop
_.drop
은 _.take
와 반대로 처음 n개의 요소를 제외한 새로운 배열을 리턴한다.n이 undefined이거나 음수인 경우 전체 배열을 shallow copy한 새로운 배열을 리턴하며, n이 배열의 길이를 초과할 경우에는 빈 배열을 리턴한다.
_.drop = function (arr, n) {
if (n === undefined || n < 0) {
let result = arr
return result
}
else if (n >= arr.length) {
return []
}
else {
let result = []
for (let i = n; i < arr.length; i++) {
result.push(arr[i])
}
return result
}
};
_.last
_.last
는 배열의 마지막 n개의 요소를 담은 새로운 배열을 리턴한다. n이 undefined이거나 음수인 경우 배열의 마지막 요소만을 담은 배열을 리턴하며, n이 배열이 길이를 초과할 경우 전체 배열을 shallow_copy한 새로운 배열을 리턴한다.
_.last = function (arr, n) {
if (n === undefined || n < 0) {
let result = [arr[arr.length-1]]
return result
}
else if (n >= arr.length) {
let result = arr
return result
}
else {
let result = []
for (let i = arr.length - n; i < arr.length; i++) {
result.push(arr[i])
}
return result
}
};
_.each
_.each
는 collection의 각 데이터에 반복적인 작업을 수행한다. _.each
는 명시적으로 어떤 값을 리턴하지 않는다.
_.each = function (collection, iteratee) {
// TODO: 여기에 코드를 작성합니다.
// console.log(collection)
// console.log(iteratee)
if (Array.isArray(collection)) {
for (let i = 0; i < collection.length; i++) {
iteratee(collection[i], i, collection)
}
}
else {
for (let key in collection) {
iteratee(collection[key], key, collection)
}
}
};
_.indexOf
_.indexOf
는 target으로 전달되는 값이 arr의 요소인 경우, 배열에서의 index를 리턴한다. 존재하지 않는 경우 -1을 리턴하며, target이 중복해서 존재하는 경우에는 가장 낮은 index를 리턴한다.
_.indexOf = function (arr, target) {
let result = -1;
_.each(arr, function (item, index) {
if (item === target && result === -1) {
result = index;
}
});
return result;
};
_.filter
_.filter
는 test 함수를 통과하는 모든 요소를 담은 새로운 배열을 리턴한다.
_.filter = function (arr, test) {
let result = []
_.each(arr, function(item, index) {
if (test(item)) {
result.push(item)
}
})
return result
};
_.reject
_.reject
는 _.filter
와 정반대로 test 함수를 통과하지 않는 모든 요소를 담은 새로운 배열을 리턴한다.
_.reject = function (arr, test) {
let result = []
_.each(arr, function(item, index) {
if (!test(item)) {
result.push(item)
}
})
return result
};
_.uniq
_.uniq
는 주어진 배열의 요소가 중복되지 않도록 새로운 배열을 리턴한다.
_.uniq = function (arr) {
let result = []
_.each(arr, function(item) {
if(_.indexOf(result, item) === -1) {
result.push(item)
}
})
return result
};
_.map
_.map
은 iteratee(반복 작업)를 arr(배열)의 각 요소에 적용한 결과를 담은 새로운 배열을 리턴한다.
_.map = function (arr, iteratee) {
let result = []
_.each(arr, function(item, index) {
result.push(iteratee(item))
})
return result
};
_.pluck
_.pluck
는 객체 또는 배열을 요소로 갖는 배열과 각 요소에서 찾고자 하는 key 또는 index를 입력받아 각 요소의 해당 값 또는 요소만을 추출하여 새로운 배열에 저장하고, 최종적으로 새로운 배열을 리턴한다.
_.pluck = function (arr, keyOrIdx) {
let result = []
_.map(arr, function(item) {
result.push(item[keyOrIdx])
})
return result
};
_.reduce
_.reduce
는 배열을 순회하며 각 요소에 iteratee 함수를 적용하고, 그 결과값을 계속해서 누적한 후, 최종적으로 누적된 결과값을 리턴한다.
_.reduce = function (arr, iteratee, initVal) {
let acc = initVal
_.each(arr, function(item, index, arr) {
if (initVal === undefined && index === 0) {
acc = item
}
else {
acc = iteratee(acc, item, index, arr)
}
})
return acc
};
_.once
_.once
는 callback 함수를 한 번만 호출하는 '함수'를 리턴한다. _.once
가 리턴하는 함수를 여러 번 호출해도 callback 함수는 한 번 이상 호출되지 않는다.
_.once = function (func) {
let isCalled = false;
let result
return function () {
if (!isCalled) {
result = func(...arguments)
isCalled = true
}
return result
};
};
_.delay
_.delay
는 입력으로 전달되는 시간(ms, 밀리초) 후, callback 함수를 함께 전달되는 인자와 함께 실행한다.
_.delay = function (func, wait, ...args) {
setTimeout(func, wait, ...args)
};
_.includes
`_.includes`는 배열이 주어진 값을 포함하는지 확인한다.
_.includes = function (arr, target) {
let flag = false
_.each(arr, function (item, index) {
if (item === target) {
flag = true
}
});
return flag
};
_.every
_.every
는 배열의 모든 요소가 test 함수(iteratee)를 통과하면 true, 그렇지 않은 경우 false를 리턴한다.
_.every = function (arr, iteratee) {
let flag = true
for (let el of arr) {
if (iteratee == undefined && !el) {
flag = false
}
else if (iteratee != undefined && !iteratee(el)) {
flag = false
}
}
return flag
};
_.some
_.some
은 배열의 요소 중 하나라도 test 함수(iteratee)를 통과하면 true를, 그렇지 않은 경우 false를 리턴한다.
_.some = function (arr, iteratee) {
// TODO: 여기에 코드를 작성합니다.
if (arr.length < 1) {
return false
}
let flag = false
for (let el of arr) {
if (iteratee == undefined && el) {
flag = true
}
else if (iteratee != undefined && iteratee(el)) {
flag = true
}
}
return flag
};
_.extend
_.extend
는 여러 개의 객체를 입력받아, 순서대로 객체를 결합한다.
_.extend = function (obj) {
_.each(arguments, function(arg) {
for(var key in arg){
obj[key] = arg[key];
}
})
return obj
};
_.defaults
_.defaults
는 `_.extend와 비슷하게 동작하지만, 이미 존재하는 속성(key)을 덮어쓰지 않는다.
_.defaults = function (obj) {
_.each(arguments, function(arg) {
for(var key in arg){
if (!obj.hasOwnProperty(key)) {
obj[key] = arg[key];
}
}
})
return obj
};
_.zip
_.zip
은 여러 개의 배열을 입력받아, 같은 index의 요소들을 묶어 배열로 만든다.
_.zip = function () {
var len = arguments[0].length
for (let arg of arguments) {
if (arg.length > len) {
len = arg.length
}
}
let result = []
for (let i = 0; i < len; i++) {
result.push([])
}
_.each(arguments, function(arg) {
for (let i = 0; i < len; i++) {
if (typeof result[i] == 'undefined') {
result[i].push(undefined)
}
else {
result[i].push(arg[i])
}
}
})
return result
};
_.zipStrict
_.zipStrict
는 _.zip
과 비슷하게 동작하지만, 최종적으로 리턴되는 배열의 각 요소의 길이는 입력으로 전달되는 배열 중 가장 "짧은" 배열의 길이로 통일된다.
_.zipStrict = function () {
var len = arguments[0].length
for (let arg of arguments) {
if (arg.length < len) {
len = arg.length
}
}
let result = []
for (let i = 0; i < len; i++) {
result.push([])
}
_.each(arguments, function(arg) {
for (let i = 0; i < len; i++) {
result[i].push(arg[i])
}
})
return result
};
_.intersection
_.intersection
은 여러 개의 배열을 입력받아 교집합 배열을 리턴한다.
_.intersection = function () {
let result = []
let set = arguments[0]
// 기준 요소를 비교
for (let el of set) {
let flag = true
_.each(arguments, function(arg) {
if (!_.includes(arg, el)) {
flag = false
}
})
if (flag) {
result.push(el)
}
}
return result
};
_.difference
_.difference
는 여러 개의 배열을 입력받아 차집합 배열을 리턴한다.
_.difference = function () {
let result = []
let keys = []
let times = [] // key가 등장한 time
for (let i = 0; i < arguments[0].length; i++) {
keys.push(arguments[0][i])
times.push(0)
}
// 기준 요소를 비교
for(let i = 1; i <arguments.length; i++) {
_.each(arguments[i], function(el) {
if (_.includes(keys, el)) {
let index = _.indexOf(keys, el)
times[index]++
}
})
}
for (let i = 0; i <times.length; i++) {
if (times[i] === 0) {
result.push(keys[i])
}
}
return result
};
_.shuffle
_.shuffle
은 배열 요소의 순서가 랜덤하게 변경된 새로운 배열을 리턴한다.
_.shuffle = function (arr) {
let arrCloned = arr.slice();
for (let fromIdx = 0; fromIdx < arr.length; fromIdx++) {
const toIdx = Math.floor(Math.random() * arr.length);
// 아래 코드는 두 변수의 값을 교환한다.
let temp = arrCloned[fromIdx];
arrCloned[fromIdx] = arrCloned[toIdx];
arrCloned[toIdx] = temp;
}
return arrCloned;
};
'기타 > 코드스테이츠 블록체인 부트캠프' 카테고리의 다른 글
Project 2: Incentive Community 클론 코딩 회고 (0) | 2022.08.29 |
---|---|
Project 1: OpenSea 클론 코딩 회고 (0) | 2022.08.16 |
[블록체인 부트캠프][회고록] Day16 (0) | 2022.05.19 |
[비동기 예제] fetch API를 이용한 네트워크 요청 (0) | 2022.05.19 |
[비동기 예제] fs 모듈을 활용한 파일 읽기 (0) | 2022.05.19 |