언더바 문제만큼은 틀리지 않겠다...!고 한다면
이번 글을 반복해서 따라한다면...무조건...?!👨🏻💻
Part.1 ~ Part.2 를 빠르게 정리합니다 :)
_ = {};
받은 값을 그대로 반환한다.
_.identity = val => val;
n이 없으면 인덱스 0값, 있으면 0~n까지 반환한다.
_.first = (arr, n) => n === undefined ? arr[0] : arr.slice(0, n)
_.first의 반대로 생각하면 된다. 뒤집고 n까지 출력해서 뒤집는다.
_.last = (arr, n) => n === undefined ? arr[arr.length - 1] : arr.reverse().slice(0, n).reverse();
forEach와 유사하게 동작한다. 배열과 객체 동작을 나누어준다.
iterator는 설명에 맞게 (값, 인덱스, 컬렉션) 순으로 넣어준다.
return은 없다.
_.each = (collection, iterator) => {
if(Array.isArray(collection)) {
for(let i = 0; i < collection.length; i += 1) {
iterator(collection[i], i, collection);
}
} else {
for(let k in collection) {
iterator(collection[k], k, collection);
}
}
};
target과 값이 일치하면 그 때의 i를 반환한다.
result === -1
조건을 추가해주는게 핵심이다.
_.indexOf = (arr, target) => {
let result = -1;
_.each(arr, (item, i) => {
item === target && (result === -1) && (result = i)
})
}
우리가 알고 있는 그 filter와 동일하다.
조건에 맞는 값만 필터링해준다.
_.each를 사용하면 배열, 객체를 포함해서 돌 수 있다.
push를 하면 되지만 전개연산자를 사용해보았다.
_.filter = (collection, test) => {
let res = [];
_.each(collection, item => test(item) && (res = [...res, item]))
return res;
}
filter의 반대이다. false일때 res에 넣으면 된다,
_.reject = (collection, test) => {
let res = [];
_.each(array, item => !res.includes(item) && res.push(item));
return res;
};
중복된 값을 제거한다.
빈 배열을 생성하고 값이 있는지 없는지 체크하면서 넣어준다.
_.uniq = arr => {
let res = [];
_.each(arr, item => !res.includes(item) && (res = [...res, item]));
return res;
}
내가 가장 많이 사용하는 고차함수이다.
컬렉션의 각 요소에 접근하여 변형시키고 배열로 리턴한다.
_.map = (collection, iterator) => {
let res = [];
_.each(collection, (item, i) => {
res = [...res, iterator(item, i, collection)]);
}
return res;
}
컬렉션의 각 요소에 접근하여 key값을 가져와 배열로 리턴한다.
_.pluck = (collection, key) => _.map(collection, obj => obj[key]);
IAT 이전에 좀 더 쉬운 방법을 알아봐야겠다.
collection의 이터레이터를 가져와서 accumulator가 없을
때는 iterator의 첫 값을 넣고, 나머지를 순회한다.
_.reduce = (collection, iterator, accumulator) => {
const iter = collection[Symbol.iterator]();
if(accumulator === undefined){
accumulator = iter.next().value;
}
for(const i of iter) {
accumulator = iterator(accumulator, i);
}
return accumulator;
};
collection의 요소와 target이 하나라도 일치하면 true이다.
기본을 false로 하고 일치할 때만 true로 바꿔준다.
_.contains = (collection, target) => {
let isTrue = false;
_.each(collection, item => item === target && (isTrue = true));
return isTrue;
}
하나라도 false이면 false / 하나라도 true이면 true
둘다 비슷하니 함께 작성한다.
iterator가 없으면 각 요소의 truthy를 체크한다.
_.every = (collection, iterator) => {
let isTrue = true;
_.each(collection, item => {
(!iterator ? !item : !iterator(item)) && (isTrue = false))
}
return isTrue;
};
_.some = (collection, iterator) => {
let isTrue = false;
_.each(collection, item => {
(!iterator ? item : iterator(item)) && (isTrue = true))
}
return isTrue;
};
obj에 뒤에 따라오는 객체를 할당한다.
arguments를 사용하면 되지만 arrow function을 위해 rest를 추가했다.
_.extend = (obj, ...rest) => {
return Object.assign(obj, ...rest)
};
_.extend와 비슷하지만 이미 존재하는 값은 덮어쓰지 않는다.
나머지 연산자로 obj 뒤의 값을 받아 순회한다.
_.defaults = (obj, ...rest) => {
for(let object of rest) {
for(let key in object) {
!obj.hasOwnProperty(key) && (obj[key] = object[key]);
}
}
return obj;
};
클로저로 isCalled를 기억시켜 다시 불릴 때 이전 값을 출력한다.
_.once = func => {
let isCalled = false;
let result;
return (...args) {
if(!isCalled) {
result = func(...args);
isCalled = true;
}
return result;
}
}
setTimeout과 유사하게 동작한다. 사용법도 동일하다.
_.delay = (func, wait, ...rest) => {
setTimeout(func, wait, ...rest)
};
중첩 배열의 각 요소에 접근하여 배열을 해제한다.
배열이면 recursion, 아니면 res에 넣는다.
_.flatten = (nestedArray, res) => {
res = res || [];
_.each(nestedArray, item => {
Array.isArray(item) ? _.flatten(item, res) : res.push(item)
});
}
이뮤터블해야하므로 받은 배열을 복사하여 잘라내어 res에 넣는다.
_.shuffle = array => {
let res = [];
let copiedArr = array.slice();
while(copiedArr.length) {
let randomIndex = Math.floor(Math.random() * copiedArr.length)
res = [...res, copiedArr.splice(randomIndex, 1)[0]];
}
return res;
}
길면서도 짧은 언더바 복습이 끝났다.
다양하게 풀어보는 방법을 연습해보라고 하셨다.
처음에 비하면 많이 바꼈으니 다양하게 공부하고 있는 것일..거다!!!
다음 편은...CheckPoint2 로 정했다~! 🤫
이제야 복습하고 있는데 복습해보는거랑 남이한거 보는거 좋더라구요! 잘봤습니다~!