S2 . 과제 UnderBar(고차함수, 비동기)

Haizel·2022년 11월 25일
1

Front-End Developer 되기

목록 보기
27/70
post-thumbnail

Underbar :

배열, 객체를 다루는 Underbar라는 라이브러리를 직접 구현해 → 자바스크립트 내장 메서드가 어떻게 콜백 함수에 활용하는지 학습하여라.

BareMinimum


1. identity

// _.identity는 전달인자(argument)가 무엇이든, 그대로 리턴합니다.
// 이 함수는 underbar의 기능 구현 및 테스트를 위해 재사용되는 함수입니다.
_.identity = function (val) {
  return val;
};

2. Slice

// _.slice는 배열의 start 인덱스부터 end 인덱스 이전까지의 요소를 shallow copy하여 새로운 배열을 리턴합니다.
_.slice = function (arr, start, end) {
 // `start`가 undefined인 경우, slice는 0부터 동작한다.
   let _start = start || 0,
       _end = end;

// 입력받은 인덱스가 음수일 경우, 마지막 인덱스부터 매칭한다. 입력받은 인덱스는 0 이상이어야 한다.
if (start < 0) _start = Math.max(0, arr.length + start);
if (end < 0) _end = Math.max(0, arr.length + end);

// `end`가 생략될 경우(undefined), slice는 마지막 인덱스까지 동작합니다.
// `end`가 배열의 범위를 벗어날 경우, slice는 마지막 인덱스까지 동작합니다.
  if (_end === undefined || _end > arr.length) _end = arr.length;
   let result = [];
// `start`가 배열의 범위를 벗어날 경우, 빈 배열을 리턴합니다.
  for (let i = _start; i < _end; i++) {
    result.push(arr[i]);
  }

  return result;
};

3. Take

_.take = function (arr, n) {
// n이 undefined이거나 음수인 경우, 빈 배열을 리턴합니다.
  if(n ===undefined || n<0){
    return [];
  }
// n이 배열의 길이를 벗어날 경우, 전체 배열을 shallow copy한 새로운 배열을 리턴합니다.
  if(n > arr.length){
    return [...arr];
  }
// _.take는 배열의 처음 n개의 element를 담은 새로운 배열을 리턴합니다.
  return _.slice(arr, 0, n);
};

**//유연님 코드(줌)**
_.take = function (arr, n) {
if(!n) return [];
return _.slice(arr, 0, n);
 };

4. Drop

_.drop = function (arr, n) {
// n이 배열의 길이를 벗어날 경우, 빈 배열을 리턴합니다.
if(n > arr.length){
    return [];
  }
// n이 undefined이거나 음수인 경우, 전체 배열을 shallow copy한 새로운 배열을 리턴합니다.
  if(n ===undefined || n<0){
    return [...arr];
  }
// _.drop는 _.take와는 반대로, 처음 n개의 element를 제외한 새로운 배열을 리턴합니다.
  return _.slice(arr,n);
};

5. Last

_.last = function (arr, n) {
// n이 undefined이거나 음수인 경우, 배열의 마지막 요소만을 담은 배열을 리턴합니다.
if(n ===undefined || n < 0){
return _.drop(arr, arr.length-1);
}
// n이 배열의 길이를 벗어날 경우, 전체 배열을 shallow copy한 새로운 배열을 리턴합니다.
if(n > arr.length){
  return [...arr];
}
// _.last는 배열의 마지막 n개의 element를 담은 새로운 배열을 리턴합니다. 
 //만약 입력받은 인덱스가 음수일 경우, 마지막 인덱스부터 매칭한다
return _.slice(arr,arr.length - n);
};

============================================================================

**//유연님 코드(줌)**
 _.last = function (arr, n) {
 if(n === undefined) return _.drop(arr,arr.length - 1);
  return _.drop(arr, arr.length -n);
 };

6. Each

/* _.each는 collection의 각 데이터에 반복적인 작업을 수행합니다.
  1. collection(배열 혹은 객체)과 함수 iteratee(반복되는 작업)를 인자로 전달받아 (iteratee는 함수의 인자로 전달되는 함수이므로 callback 함수)
  2. collection의 데이터(element 또는 property)를 순회하면서
  3. iteratee에 각 데이터를 인자로 전달하여 실행합니다.
  iteratee에는 테스트 케이스에 따라서 다양한 함수가 할당됩니다. */
/* iterator : 반복을 해주는 함수 , iteratee : 반복을 당하는 함수 */

// _.each는 명시적으로 어떤 값을 리턴하지 않습니다.
_.each = function (collection, iteratee) {
//1. collection이 배열인지 객체인지 확인
if(Array.isArray(collection)){   //true, 배열일 때,
  for(let i = 0; i < collection.length; i++){ 
  //배열 arr을 입력받을 경우, iteratee(ele, idx, arr)
  iteratee(collection[i], i, collection)
  } 
 } else {  //false, 객체일 때,
  for(let key in collection){
  //객체 obj를 입력받을 경우, iteratee(val, key, obj)
  iteratee(collection[key], key, collection)
  }
 }
};

//true, 배열일 때 조건문을 [for of 문]으로 작성하고 싶다면,
 let index = 0;
  for(let value of collection){
   iteratee(value, index, collection)
    index++;
   }

7. 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 === -1을 비교하는 이유는 target값이 중복해서 존재하는 경우, 가장 낮은 index를 리턴하기 위해서이다.
      result = index;
    }
  });

  return result;
};

8. Filter

// _.filter는 test 함수를 통과하는 모든 요소를 담은 새로운 배열을 리턴합니다.
// test(element)의 결과(return 값)가 truthy일 경우, 통과입니다(test 함수는 각 요소에 반복 적용됩니다)
_.filter = function (arr, test) {
	//boolean으로 element 나누기 -> callback 1번째
let newArr = [];
//배열의 모든 요소를 함수에 적용시키기
_.each(arr, function(condition){ 
    if(test(condition)){  
      newArr.push(condition);
    }
  });
  return newArr;
};

9. Reject

// _.reject는 _.filter와 정반대로 test 함수를 통과하지 않는 모든 요소를 담은 새로운 배열을 리턴합니다.
_.reject = function (arr, test) {
let newArr = [];
  _.each(arr, function(condition){ 
      if(!test(condition)){  
        newArr.push(condition);
      }
    });
    return newArr;
};

10. Uniq

// _.uniq는 주어진 배열의 요소가 중복되지 않도록 새로운 배열을 리턴합니다.
_.uniq = function (arr) {
let newArr = [];
  _.each(arr, function(item, index){
    if(_.indexOf(arr, item) === index){
      newArr.push(item);
    }
  })
return newArr;
}

=======================================================================

**//유연님 코드(줌)**
_.uniq = function (arr) {
  let result = [];
  _.each(arr, (element) => {
  //result 배열에 반복적으로 돌고있는 arr의 element 값이 있으면 무시
  //없다면 result에 푸시
  if(_.indexOf(result, element) === -1){
   result.push(element)
   }
 })
return result;
  }

11. Map

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

_.map = function (arr, iteratee) {
let newArr = [];
 _.each(arr, function(item){
  //iteratee를 배열의 각 요소에 적용한 새로운 배열을 리턴하라
  newArr.push(iteratee(item));
 })
 return newArr;
};

12. Pluck

//  1. /객체 또는 배열을 요소로 갖는/ 배열과 각 요소에서 찾고자 하는 /key 또는 index/를 입력받아
//  2. 각 요소의 /해당 값 또는 요소만을 추출/하여 새로운 배열에 저장하고,
//  3. 최종적으로 새로운 배열을 리턴합니다.
// 최종적으로 리턴되는 새로운 배열의 길이는 입력으로 전달되는 배열의 길이와 같아야 합니다.
// 따라서 찾고자 하는 key 또는 index를 가지고 있지 않은 요소의 경우, 추출 결과는 undefined 입니다.

_.pluck = function (arr, keyOrIdx) {
return _.map(arr, function(el){
    return el[keyOrIdx];
  })
}

**//_.pluck을 _.each를 사용해 구현한다면,**
_.pluck = function (arr, keyOrIdx) {
 let result = [];
   _.each(arr, function (item) {
     result.push(item[keyOrIdx]);
   });
   return result;
  }

13. Reduce

// _.reduce는
//  1. 배열을 순회하며 각 요소에 iteratee 함수를 적용하고,
//  2. 그 결과값을 계속해서 누적(accumulate)합니다.
//  3. 최종적으로 누적된 결과값을 리턴합니다.
// _.reduce는 반복해서 값을 누적하므로 이 누적되는 값을 관리해야 합니다.
// 따라서 _.reduce의 iteratee는 인자가 하나 더 추가되어 최종 형태는 아래와 같습니다.
//  iteratee(acc, ele, idx, arr)
// _.reduce는 세 번째 인자로 초기 값을 전달받을 수 있습니다.
// 이 세 번째 인자로 초기 값이 전달되는 경우, 그 값을 누적값의 기초(acc)로 하여 배열의 '첫 번째' 요소부터 반복 작업이 수행됩니다.
// 반면 초기 값이 전달되지 않은 경우, 배열의 첫 번째 요소를 누적값의 출발로 하여 배열의 '두 번째' 요소부터 반복 작업이 수행됩니다.
// 따라서 최종적인 형태는 아래와 같습니다.
//  _.reduce(arr, iteratee, initVal) //initVal은 초기값을 의미(없다면, 초기값은 배열의 첫 요소가 된다)
//  iteratee(acc, ele, idx, arr)

 //함수 iteratee(반복적인 작업을 하는 함수,함수의 인자로 전달되는 함수이므로 callback 함수)는 
//데이터(element 또는 property)를 순회하면서 -> iteratee에 각 데이터를 인자로 전달하여 실행합니다.
// iteratee에는 테스트 케이스에 따라서 다양한 함수가 할당됩니다.

_.reduce = function (arr, iteratee, initVal) {
let acc = initVal;
  _.each(arr, function(ele, idx){
    if(acc === undefined){ //1. 초기값이 없다면 
      acc = ele;
      //-> 배열의 첫번째 요소인 acc부터 현재값으로 더한다.
    } else {  //2. 만약 초기값이 있다면,
    acc = iteratee(acc, ele, idx, arr);
    // -> acc + ele ..를 누적으로 더한 값을 acc에 할당한다.
    }
  })
  // -> 누적값을 반환하라.
  return acc;
};
profile
한입 크기로 베어먹는 개발지식 🍰

0개의 댓글