여기부턴 정말 어려웠다...😂
arrow function에서 arguments가 안 써지는걸 이제 알았다...;


Object

_.extend

헤메다가 한 번 푸니까 세 가지 방법으로 풀 수 있었다...!
obj가 어떻게 들어오는지 몰라서 많이 헷갈렸던 문제이다.
obj는 일반적인 객체 (ex: {a : 1}) 이런식으로 들어온다.
그리고, 나머지는 arguments로 받으면 쉽게 풀 수 있다.

// SOL 1 (이때는 => 와 ...rest를 사용하지 않는다.)
_.extend = function(obj) { 
  // 주어진 객체를 전달된 모든 속성으로 확장합니다.
  for(let i = 1; i < arguments.length; i++){
    Object.assign(obj, arguments[i]);
  }
  return obj;
}
// SOL 2 : 화살표 함수 이용
_.extend = (obj, ...rest) => {
   for(const a of rest) {
     Object.assign(obj, a);
   }
   return obj;
 };
// SOL 3 : 화살표 + _.each 이용
_.extend = (obj, ...rest) => {
   _.each(rest, (item) => {
     Object.assign(obj, item)
   })
   return obj;
};

_.defaults

_.extend와 비슷해서 쉬울 줄 알았는데, 전혀 아니다...;
전개연산자로 받으면 객체를 둘러싼 배열로 들어온다.
이걸 for-of으로 돌아서 각 parameter를 꺼내주고,
그 객체를 for-in으로 돌아서 key를 가져온다.

_.defaults = (obj, ...rest) => {
    for(const param of rest) {
      for(const k in param) {
          obj.hasOwnProperty(k) ? obj : (obj[k] = param[k])
      }
    }
    return obj;
 };

_.once

함수내에서 scope가 중요하다.
arguments를 사용하지 않고 풀고 싶었지만 쉽지가 않았다.
함수 내의 함수에서 바깥의 변수를 사용하면 클로저로 사용된다.
조금 더 이해하게 된다면 전개연산자만으로 만들어 보고 싶다 :)

// 최대 한번만 호출할 수 있는 함수를 리턴합니다. 이후의 호출은 이전에 한번 리턴된 값만을 리턴해야 합니다.
_.once = (func) => {
  let alreadyCalled = false;
  let result;
  return function() {
    // TIP: arguments 키워드 혹은, spread operator를 사용하세요.
    if(alreadyCalled === false) {
      result = func(...arguments)
      alreadyCalled = true;
    } 
    return result;
  };
};

_.delay

setTimeout과 동작 방식이 동일해서 간단하게 풀었다.

// setTimeout(func[, delay, param1, param2, ...])
_.delay = (func, wait, ...rest) => {
  setTimeout(func, wait, ...rest)
};

👉🏻여기까지가 기본 과제이고, 이후 Advanced를 차차 풀어보겠다 :)