언더바 문제만큼은 틀리지 않겠다...!고 한다면
이번 글을 반복해서 따라한다면...무조건...?!👨🏻‍💻
Part.1 ~ Part.2 를 빠르게 정리합니다 :)


0. _ 설정

_ = {};

1. _.identity

받은 값을 그대로 반환한다.

_.identity = val => val;

2. _.first

n이 없으면 인덱스 0값, 있으면 0~n까지 반환한다.

_.first = (arr, n) => n === undefined ? arr[0] : arr.slice(0, n)

3. _.last

_.first의 반대로 생각하면 된다. 뒤집고 n까지 출력해서 뒤집는다.

_.last = (arr, n) => n === undefined ? arr[arr.length - 1] : arr.reverse().slice(0, n).reverse();

4. _.each

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);
    }
  }
};

5. _.indexOf

target과 값이 일치하면 그 때의 i를 반환한다.
result === -1 조건을 추가해주는게 핵심이다.

_.indexOf = (arr, target) => {
  let result = -1;
  _.each(arr, (item, i) => {
    item === target && (result === -1) && (result = i)
  })
}

6. _.filter

우리가 알고 있는 그 filter와 동일하다.
조건에 맞는 값만 필터링해준다.
_.each를 사용하면 배열, 객체를 포함해서 돌 수 있다.
push를 하면 되지만 전개연산자를 사용해보았다.

_.filter = (collection, test) => {
  let res = [];
  _.each(collection, item => test(item) && (res = [...res, item]))
  return res;
}

7. _.reject

filter의 반대이다. false일때 res에 넣으면 된다,

_.reject = (collection, test) => {
  let res = [];
  _.each(array, item => !res.includes(item) && res.push(item));
  return res;
};

8. _.uniq

중복된 값을 제거한다.
빈 배열을 생성하고 값이 있는지 없는지 체크하면서 넣어준다.

_.uniq = arr => {
  let res = [];
  _.each(arr, item => !res.includes(item) && (res = [...res, item]));
  return res;
}

9. _.map

내가 가장 많이 사용하는 고차함수이다.
컬렉션의 각 요소에 접근하여 변형시키고 배열로 리턴한다.

_.map = (collection, iterator) => {
  let res = [];
  _.each(collection, (item, i) => {
    res = [...res, iterator(item, i, collection)]);
  }
  return res;
}

10. _.pluck

컬렉션의 각 요소에 접근하여 key값을 가져와 배열로 리턴한다.

_.pluck = (collection, key) => _.map(collection, obj => obj[key]);

11. _.reduce

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;
};

12. _.contains

collection의 요소와 target이 하나라도 일치하면 true이다.
기본을 false로 하고 일치할 때만 true로 바꿔준다.

_.contains = (collection, target) => {
  let isTrue = false;
  _.each(collection, item => item === target && (isTrue = true));
  return isTrue;
}

13. _.every & _.some

하나라도 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;
};

14. _.extend

obj에 뒤에 따라오는 객체를 할당한다.
arguments를 사용하면 되지만 arrow function을 위해 rest를 추가했다.

_.extend = (obj, ...rest) => {
  return Object.assign(obj, ...rest)
};

15. _.defaults

_.extend와 비슷하지만 이미 존재하는 값은 덮어쓰지 않는다.
나머지 연산자로 obj 뒤의 값을 받아 순회한다.

_.defaults = (obj, ...rest) => {
  for(let object of rest) {
    for(let key in object) {
      !obj.hasOwnProperty(key) && (obj[key] = object[key]);
    }
  }
  return obj;
};

16. _.once

클로저로 isCalled를 기억시켜 다시 불릴 때 이전 값을 출력한다.

_.once = func => {
  let isCalled = false;
  let result;
  return (...args) {
    if(!isCalled) {
      result = func(...args);
      isCalled = true;
    }
    return result;
  }
}

17. _.delay

setTimeout과 유사하게 동작한다. 사용법도 동일하다.

_.delay = (func, wait, ...rest) => {
  setTimeout(func, wait, ...rest)
};

18. _.flatten

중첩 배열의 각 요소에 접근하여 배열을 해제한다.
배열이면 recursion, 아니면 res에 넣는다.

_.flatten = (nestedArray, res) => {
  res = res || [];
  _.each(nestedArray, item => {
    Array.isArray(item) ? _.flatten(item, res) : res.push(item)
  });
}

19. _.shuffle

이뮤터블해야하므로 받은 배열을 복사하여 잘라내어 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 로 정했다~! 🤫