underbar(Bare Minimum)

왕지호·2022년 11월 22일
0

오늘은 자체 내장된 고차함수를 사용하지 않고 고차함수가 어떤 방식으로 작동되는지 알아보는 과제를 알아보자!

Bare Minimum Requirement

  • 자주 사용되는 기본적인 JavaScript의 배열 메서드를 직접 구현하며 원리를 이해한다.(slice, forEach, indexOf, filter, map, reduce 등)
  • 고차 함수(Higher order function)를 활용하여 기존에 만든 함수를 콜백 함수로 재사용할 수 있다.
  • iteratee가 콜백 함수임을 이해할 수 있다.

_.identity는 전달인자(argument)가 무엇이든, 그대로 리턴합니다.

  • 이 함수는 underbar의 기능 구현 및 테스트를 위해 재사용되는 함수입니다.
_.identity = function (val) {
  // TODO: 여기에 코드를 작성합니다.
  return val;
};

_.take는 배열의 처음 n개의 element를 담은 새로운 배열을 리턴합니다.

  • n이 undefined이거나 음수인 경우, 빈 배열을 리턴합니다.
  • n이 배열의 길이를 벗어날 경우, 전체 배열을 shallow copy한 새로운 배열을 리턴합니다.
_.take = function (arr, n) {
  // TODO: 여기에 코드를 작성합니다.
  //내가 작성한 코드
  /* let result = [];
  if (n >= arr.length) return arr;
  for (let i = 0; i < n; i++) {
    if (n < 0 || n === undefined) return [];
    else result.push(arr[i]);
  }
  return result; */
  //더 간단한 코드
  if (!n) return [];
  return _.slice(arr, 0, n);
};

_.drop는 _.take와는 반대로, 처음 n개의 element를 제외한 새로운 배열을 리턴합니다.

  • n이 undefined이거나 음수인 경우, 전체 배열을 shallow copy한 새로운 배열을 리턴합니다.
  • n이 배열의 길이를 벗어날 경우, 빈 배열을 리턴합니다.
_.drop = function (arr, n) {
  // TODO: 여기에 코드를 작성합니다.
  //내가 작성한 코드
  /* let result = [];
  if (n >= arr.length) return result;
  for (let i = 0; i < arr.length; i++) {
    if (n < 0 || n === undefined) result.push(arr[i]);
    else if (i >= n) result.push(arr[i]);
  }
  return result; */
  //더 간단힌 코드
  let result = [];
  if (!n) {
    result = arr;
    return result;
  }
  for (let i = n; i < arr.length; i++) {
    if (arr[i]) result.push(arr[i]);
  }
  return result;
};

_.last는 배열의 마지막 n개의 element를 담은 새로운 배열을 리턴합니다.

  • n이 undefined이거나 음수인 경우, 배열의 마지막 요소만을 담은 배열을 리턴합니다.
  • n이 배열의 길이를 벗어날 경우, 전체 배열을 shallow copy한 새로운 배열을 리턴합니다.
  • .take와 .drop 중 일부 또는 전부를 활용할 수 있습니다.
_.last = function (arr, n) {
  // TODO: 여기에 코드를 작성합니다.
  // 내가 작성한 코드
  /* let result = [];
  if (n === undefined || n < 0) {
    result.push(arr[arr.length - 1]);
  } else if (n >= arr.length) {
    return arr;
  } else return _.slice(arr, arr.length - n, arr.length);
  return result; */
  // 더 간단한 코드
  if (n === undefined) return _.drop(arr, arr.length - 1);
  return _.drop(arr, arr.length - n);
};

_.each는 명시적으로 어떤 값을 리턴하지 않습니다.

_.each = function (collection, iteratee) {
  // TODO: 여기에 코드를 작성합니다.
  if (Array.isArray(collection)) {
    for (let i = 0; i < collection.length; i++) {
      iteratee(collection[i], i, collection);
    }
  } else if (typeof collection === "object") {
    for (let key in collection) {
      iteratee(collection[key], key, collection);
    }
  }
};

_.indexOf는 target으로 전달되는 값이 arr의 요소인 경우, 배열에서의 위치(index)를 리턴합니다.

  • 그렇지 않은 경우, -1을 리턴합니다.
  • target이 중복해서 존재하는 경우, 가장 낮은 index를 리턴합니다.
_.indexOf = function (arr, target) {
  // 배열의 모든 요소에 접근하려면, 순회 알고리즘(iteration algorithm)을 구현해야 합니다.
  // 반복문을 사용하는 것이 가장 일반적이지만, 지금부터는 이미 구현한 _.each 함수를 활용하여야 합니다.
  // 아래 _.indexOf의 구현을 참고하시기 바랍니다.
  let result = -1;
  _.each(arr, function (item, index) {
    if (item === target && result === -1) {
      result = index;
    }
  });
  return result;
};

_.filter는 test 함수를 통과하는 모든 요소를 담은 새로운 배열을 리턴합니다.

  • test(element)의 결과(return 값)가 truthy일 경우, 통과입니다.
  • test 함수는 각 요소에 반복 적용됩니다.
_.filter = function (arr, test) {
  // TODO: 여기에 코드를 작성합니다.
  let result = [];
  _.each(arr, function (el) {
    if (test(el)) result.push(el);
  });
  return result;
};

_.reject는 _.filter와 정반대로 test 함수를 통과하지 않는 모든 요소를 담은 새로운 배열을 리턴합니다.

_.reject = function (arr, test) {
  // TODO: 여기에 코드를 작성합니다.
  let result = [];
  _.each(arr, function (el) {
    if (!test(el)) result.push(el);
  });
  return result;
};

_.uniq는 주어진 배열의 요소가 중복되지 않도록 새로운 배열을 리턴합니다.

  • 중복 여부의 판단은 엄격한 동치 연산(strict equality, ===)을 사용해야 합니다.
  • 입력으로 전달되는 배열의 요소는 모두 primitive value라고 가정합니다.
_.uniq = function (arr) {
  // TODO: 여기에 코드를 작성합니다.
  let result = [];
  _.each(arr, function (el) {
    for (let i = 0; i < arr.length; i++) {
      if (result[i] === el) {
        return false;
      }
    }
    result.push(el);
  });
  return result;
};

_.map은 iteratee(반복되는 작업)를 배열의 각 요소에 적용(apply)한 결과를 담은 새로운 배열을 리턴합니다.

  • 함수의 이름에서 드러나듯이 _.map은 배열의 각 요소를 다른 것(iteratee의 결과)으로 매핑(mapping)합니다.
_.map = function (arr, iteratee) {
  // TODO: 여기에 코드를 작성합니다.
  // _.map 함수는 매우 자주 사용됩니다.
  // _.each 함수와 비슷하게 동작하지만, 각 요소에 iteratee를 적용한 결과를 리턴합니다.
  let result = [];
  _.each(arr, function (el) {
    result.push(iteratee(el));
  });
  return result;
};

_.pluck

    1. 객체 또는 배열을 요소로 갖는 배열과 각 요소에서 찾고자 하는 key 또는 index를 입력받아
    1. 각 요소의 해당 값 또는 요소만을 추출하여 새로운 배열에 저장하고,
    1. 최종적으로 새로운 배열을 리턴합니다.
  • 예를 들어, 각 개인의 정보를 담은 객체를 요소로 갖는 배열을 통해서, 모든 개인의 나이만으로 구성된 별도의 배열을 만들 수 있습니다.
  • 최종적으로 리턴되는 새로운 배열의 길이는 입력으로 전달되는 배열의 길이와 같아야 합니다.
  • 따라서 찾고자 하는 key 또는 index를 가지고 있지 않은 요소의 경우, 추출 결과는 undefined 입니다.
_.pluck = function (arr, keyOrIdx) {
  // _.pluck을 _.each를 사용해 구현하면 아래와 같습니다.
  // let result = [];
  // _.each(arr, function (item) {
  //   result.push(item[keyOrIdx]);
  // });
  // return result;
  // _.pluck은 _.map을 사용해 구현하시기 바랍니다.
  // TODO: 여기에 코드를 작성합니다.
  let result = [];
  _.map(arr, function (el) {
    result.push(el[keyOrIdx]);
  });
  return result;
};

_.reduce

    1. 배열을 순회하며 각 요소에 iteratee 함수를 적용하고,
    1. 그 결과값을 계속해서 누적(accumulate)합니다.
    1. 최종적으로 누적된 결과값을 리턴합니다.
_.reduce = function (arr, iteratee, initVal) {
  // TODO: 여기에 코드를 작성합니다.
  let acc = initVal;
  _.each(arr, function (ele, idx) {
    if (initVal === undefined && idx === 0) {
      acc = ele;
    } else acc = iteratee(acc, ele, idx, arr);
  });
  return acc;
};
profile
개발 공부하는 코린이!

0개의 댓글