2020. 12. 29 / Underbar Test (1/2)

Mono crom·2021년 1월 8일
0

언더스코어 함수구현 part 1.

멘탈 터져서 하루종일 멍하니 페어가 시키는대로 손가락만 움직이다 일정이 끝나버렸다.

오늘 이거 박살내고 잔다. 다 죽어따 진짜...


_.each


_.each = function (collection, iteratee) {  
  
  if(Array.isArray(collection)) { 
    for(let i = 0; i < collection.length; i++) { // collection이 배열이면
      iteratee(collection[i], i, collection); 
    }    
    
  } else if(typeof collection === 'object') { // collection 이 객체면
    for (let key in collection) {
      iteratee(collection[key], key, collection);
    }
  }
  
};
  1. each 함수에는 collection(배열이나 객체) 와 정체모를 함수 iteratee 가 인자로 들어온다.

  2. 물론 인자의 명칭은 아무 상관도 없으므로 (tomato, potato) 가 되어도 무관하다. iteratee 함수에 요소(값), 인덱스(키), 배열(객체) 순으로 인자를 처리해 collection에 적용하는게 핵심이다.

  3. 배열은 요소들에 순서가 있으나 객체는 순서가 없어 요소에 접근하는 방식에 차이가 생기므로, if문을 통해 collection 이 배열인지 객체인지를 구분해 따로 로직을 짜야 한다.

  4. 배열의 길이만큼 for문을 돌리면서 iteratee 함수를 실행시키는데, 그 인자로 배열의 요소, 인덱스, 배열 을 순서대로 집어넣고 실행시킨다. iteratee 함수는 그 3가지 인자를 다뤄서 정체모를 계산작업을 하게 된다.

  5. collection이 객체인 경우에도 접근하는 문법의 종류만 다르고 작동원리는 위에 배열이랑 똑같다. collection 의 key 에 for문으로 접근해서 iteratee 함수에 value, key, 객체 인자를 넣어 실행시킨다.


_.filter

_.filter = function (arr, test) {

  let newArr = [];
  
  _.each(arr, function(ele) {
    if(test(ele)) {
      newArr.push(ele)
    }    
  });
  
  return newArr;
};
  1. arr 요소들에 test함수를 적용해 결과가 true 인 요소만을 담은 새로운 배열을 리턴시키는 filter 함수. test 는 인자를 입력받아 boolean 값을 리턴하는 함수다.

  2. each 함수를 통해 filter의 핵심기능을 구현할건데, 1번인자로 filter함수의 인자인 arr를 입력한다. 그리고 2번인자로 익명함수를 하나 구현해서 입력한다. 이 익명함수가 하는 일은 1번 인자의 요소들에 test 함수를 적용해 true인 것만 newArr 에 푸쉬하는 것이다.


_.reject

_.reject = function (arr, test) {
  
  let newArr = [];
  
  return _.filter(arr, function(item) {
    return !test(item)
  })
  • filter와 정 반대의 기능, 즉 test 함수에서 false 값이 나오는 것만 담은 새로운 배열을 리턴하는 함수. filter 함수와 로직이 완전히 동일하므로 설명은 생략.

_.uniq

_.uniq = function (arr) {
  
  let newArr =[];
  
  _.each(arr, function(el) {
    for(let i = 0; i < newArr.length; i++) {
      if(el === newArr[i]) {
        return;
      }
    }
    newArr.push(el)
  });
  
  return newArr;
};
  1. arr에서 중복되는 요소를 요소를 담은 새로운 배열을 리턴하는 함수. each함수를 필수적으로 사용해야 하는 조건이 걸려있다.

  2. each함수를 실행시키면서 두 번째 인자로 익명함수를 넘겨준다. 이 익명함수는 for문을 돌리며 newArr 내부에 el과 동일한 요소가 존재하지 않으면 그 el을 newArr에 푸쉬한다.

  3. 가령 arr의 2번 인덱스 요소인 '2'가 이미 newArr에 푸쉬되었다면, 3번 인덱스에 중복되는 '2'가 존재하더라도 if문에서 걸리기 때문에 푸쉬되지 않고 리턴되어 버린다.

  4. each함수 때문에 return되었다고 함수가 끝나는게 아니라 그 다음 el 이 투입되어 다음 for문이 또 돌아간다.


_.map

_.map = function (arr, iteratee) { 

  let newArr = [];

  _.each(arr, function(ele) {
        newArr.push(iteratee(ele));
  });
  
  return newArr;
}
  1. arr의 각 요소에 iteratee 함수를 적용해서 그 결과요소들을 담은 새로운 배열을 리턴하는 함수.

  2. 슬슬 익숙해진다. each 함수를 사용해야 하고, 상술한 기능을 수행하는 익명함수를 2번째 인자에 넣어야 할거다.

  3. map함수와 each함수의 차이는 each 함수는 그저 2번째인자로 들어오는 함수를 arr의 각 요소에 적용하는 데 그치지만, map 함수는 적용된 요소들을 새로운 배열에 담아서 그 배열을 리턴하는 기능까지 한다는 점이다.

이 점을 체크하고 아래 함수를 보자.


_.pluck

_.pluck = function (arr, keyOrIdx) {
  return _.map(arr, function(ele) { 
    return ele[keyOrIdx];
  })
}
  1. map 함수를 사용해, 배열 또는 객체를 요소로 같는 배열 arr 에서 keyOrIdx 에 해당하는 요소를 찾아 그 요소를 담은 새로운 배열을 리턴하는 함수이다.

  2. map 함수를 실행시키면서 두 번째 인자로 익명함수를 전달하는데, 이 익명함수는 arr의 keyOrIdx 요소를 찾아 리턴한다.

  3. 하나 더, each 함수는 내부에서 리턴되는 결과물이 없지만 map 함수는 직접 새로운 배열을 리턴하기 때문에 map() 을 리턴시키면 된다. 실수하기 쉬우므로 유의해야 한다.

  4. 응용하자면, 굳이 map함수를 쓰지 않고 each 함수만을 사용해 동일한 기능을 구현할 수도 있다. 이 경우 ele[keyOrIdx] 를 newArr 에 푸쉬하고 함수 종료 후 newArr을 리턴해주면 된다.


_.reduce

_.reduce = function (arr, iteratee, initVal) {
  let acc = initVal; 

  _.each(arr, function(el, idx){
    if(acc === undefined){
      acc = el;
    }else{
      acc = iteratee(acc, el, idx, arr); 
    }
  });

  return acc;
};
  1. arr 요소들에 iteratee 함수를 적용하면서 그 누적치를 쌓아올려 그 값을 리턴시키는 함수. iteratee 함수는 (누적치, 요소, 인덱스, 배열) 인자를 입력받을 수 있어야 한다. 최초에 누적치는 초기값, 즉 initVal 로부터 시작되므로 acc는 처음에 initVal 을 할당받는다.

  2. each함수를 실행시키면서 2번째 인자로 익명함수를 전달한다. 중요한건 이 익명함수의 기능을 이해하는 것이겠지? if문은 initVal 이 설정되어 있는 경우아닌 경우의 분기를 나눈다. initVal에 값이 할당되지 않았다면 2번줄에서 acc 에 undefined 가 할당되었을 것이다.

  3. acc가 undefined 인 경우, 가장 먼저 투입된 el, 즉 arr[0]을 acc에 재할당해줘야 한다. 그 다음 순회, arr[1]이 투입되었다. acc가 더이상 undefined가 아니니까 else문으로 빠진다.

  4. 이제 본격적으로 iteratee 함수가 작용하고, 그 결과값이 acc에 누적되기 시작한다.

  5. iteratee 함수의 인자로 변수 acc, each함수를 통해 투입되는 arr의 요소 el인덱스 idx, arr 자체를 전달한다. 그러한 인자를 투입받아 interatee 는 어떤 기능을 수행하고, 그 결과값이 acc 에 저장된다. 저장된 acc 는 그 다음 순회에서 intertee 의 첫 번째 인자로 다시 전달된다. 이렇게 acc가 누적된다.


profile
니가 진짜로 원하는게 뭐야

0개의 댓글