💻/[과제]

[과제] Underbar

Mia_ 2022. 12. 2. 17:49

Bare Minimum Requirement

- 이번 스프린트에서 사용 가능한 내장 메소드 : Array.prototype의 'pop', 'push', 'shift', 'sort' 로 한정됨. 다른 메소드 사용 금지!

- 단 새로운 함수 구현시 이전에 구현함 함수 활용 가능

 

identity

- _.identity는 전달인자가 무엇이든 그대로 리턴

- 이 함수는 underbar의 기능 구현 및 테스트를 위해 재사용되는 함수

_.identity = function (val) {

  return val;
};

 

slice

- _.slice는 배열의 start 인덱스 부터 end 인덱스 이전 까지의 요소를 shallow copy하여 새로운 배열 리턴

_.slice = function (arr, start, end) {

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


  // `end`가 생략될 경우(undefined), slice는 마지막 인덱스까지 동작
  // `end`가 배열의 범위를 벗어날 경우, slice는 마지막 인덱스까지 동작
  if (_end === undefined || _end > arr.length) 
    _end = arr.length;

  // `start`가 배열의 범위를 벗어날 경우, 빈 배열을 리턴합니다.
  let result = [];
  for (let i = _start; i < _end; i++) {
    result.push(arr[i]);
  }

  return result;
};

- slice 메소드 : 어떤 배열의 begin부터 end 까지 (end 미포함)에 대한 얕은 복사본을 새로운 배열 객체로 반환 

- slice 메소드의 두 번째 인자가 음수인 경우 뒤에서 인덱스를 하나씩 카운트해서 요소를 제하고 출력해야 하는다는 것이 포인트

 

 

 take

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

- n이 undefiend이거나 음수인 경우, 빈 배여 리턴

- n이 배열의 길이를 벗어날 경우, 전체 배열을 shallow copy한 새로운 배열 리턴

- 1. 내가 풀어본 방법

_.take = function (arr, n) {

  let start = 0; //'start'가 undefined인 경우, 0부터 동작
  let end = n; //받은 n이 마지막 인덱스

  //'end'가 범위를 벗어날 경우 마지막 인덱스까지 동작
  if(end > arr.length)
    end = arr.length; 
  
  //'end'가 입력되지 않은 경우 빈배열 리턴
  if(end === undefined) return []; 

  let result = [];
  for(let i = start; i < end; i++){
    result.push(arr[i]);
  }

   return result;  
};

- 2. 줌 세션 시간에 설명해 주신 코드

_.take = function (arr, n) {

  // _.slice 활용 ver.
  // 0이 falsey한 값이라 0인게 ture 값이 될려면 !n --> n이 0이면 true가 나옴
  if(!n) return [];
   return _.slice(arr, 0, n);
};

 

 

drop

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

- n이 undefined이거나 음수인 경우, 전체 배열을 shallow copy한 새로운 배열 리턴

- n이 배열의 길이를 벗어난 경우 빈 배열 리턴

_.drop = function (arr, n) {

  let start = n; 
  let end = arr.length; //마지막 인덱스 까지

  //'start'가 입력되지 않은 경우 전체 배열 리턴
  if(start === undefined) 
    start = 0; 

  let result = [];
  for(let i = start; i < end; i++){
    result.push(arr[i]);
  }
  return result;

};

 

 

last

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

- n이 undefined이거나 음수인 경우, 배열의 마지막 요소만을 담은 배열을 리턴

- n이 배열의 길이를 벗어날 경우, 전체 배열의  shallow copy한 새로운 배열 리턴

- 1. 내가 풀어본 방법

_.last = function (arr, n) {

  let start = arr.length-n;
  let end = arr.length; 
  
  //n이 입력되지 않은 경우, 배열의 마지막 요소만 담은 배열 리턴
  if(n === undefined)
    start = arr.length-1; 
  
  //n 이 배열의 길이를 벗어날 경우, 배열 전체 리턴
  if(n > arr.length)
  start = 0; 

  let result = [];
  for(let i = start; i < end; i++){
    result.push(arr[i]);
  }
  return result;
};

- 2. 줌 세션 시간에 설명해 주신 코드

_.last = function (arr, n) {
  // _.take과 _.drop 활용 ver
  
  // n이 undefined일 경우 마지막 요소만 담은 배열 리턴
  if(n === undefined) 
    return _.drop(arr, arr.length - 1);
    
  // n이 배열의 길이를 벗어나면 전체 배열 리턴
  if(n > arr.length)
    return _.take(arr, arr.length);
  else    
  return _.drop(arr, arr.length - n);
};

 

 

each

- _.each는 명시적으로 어떤 값을 리턴하지 않음

- _.each는 collection의 각 데이터에 반복적인 작업을 수행

- 1. collection과 함수 iteratee를 인자로 전달 받아

- 2. collection의 데이터를 순회하면서

- 3. iteractee(반복자)에 각 데이터를 인자로 전달하여 실행

- collection은 배열 혹은 객체, iteratee는 반복 작업, 콜백 함수 

 

_.each = function (collection, iteratee) {

  //배열을 입력받은 경우 
  if(Array.isArray(collection)) {    
      for(let i = 0; i < collection.length; i++){
        iteratee(collection[i], i, collection); //iteratee(ele, inx, arr) 
      }
  //객체를 입력 받은 경우   
  } else if(typeof collection === 'object') {
    for(let key in collection){  //for..in 구문은 key값은 접근이 가능하나 value 값은 불가능
      iteratee(collection[key], key, collection); //iteratee(val, key, obj)
    }
  } 
};

 

 

indexOf

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

- 그렇지 않은 경우 -1를 리턴

- target이 중복해서 존재하는 경우, 가장 낮은 index를 리턴

_.indexOf = function (arr, target) {
  // target이 arr의 요소가 아닌 경우
  let result = -1;

  _.each(arr, function (item, index) {
    if (item === target && result === -1) {
      result = index;
    }
  });

  return result;
};

 

 

filter

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

- test(element)의 결과(return)가 truthy일 경우 통과

- test는 각 요소에 반복 적용 

- arr.filte(원하는 조건이 참이도록 작성한 함수)

_.filter = function (arr, test) {

  let result = [];
  //1. test라는 함수 안에 arr의 요소들이 인수로 하나씩 들어가야 함 --> test(arr의 요소들)
  //2. test(arr의 요소들)를 통과한 값들만 담은 배열 리턴
  
  _.each(arr, function (el) {
    if(test(el)){ // 2.
      result.push(el);
    }  
  });
  return result;
};

 

 

reject

- _.reject는 _.filter와 정반대로 test에 통과하지 못한 요소들만 담은 새로운 배열 리턴

_.reject = function (arr, test) {
  
  let result = [];
  _.each(arr, function(el){
    if(!(test(el))){ //._filter에서 truthy한 요소들만 통화 시켰음. 이걸 단항 연산자 !를 사용해 뒤집음
      result.push(el); //result에는 함수를 통과한 요소들만 있음
    }
  });
  return result;
};

 

 

uniq

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

- 중복 여부에 판단은 엄격한 동치 연산 (strict equality, ===)을 사용해야 함

- 입력으로 전달되는 배열의 요소는 모두 primitive라고 가정

 

- indexOf는 인수에 있는 배열의 값의 인덱스 값을 반환함. 중복 값은 가장 작은 인덱스 값을 가지는 인덱스 번호만 반환

- indexOf는 만약에 배열 안에 그 요소가 없으면 -1를 반환

_.uniq = function(arr){
  let result = [];
  _.each(arr,fucntion(el){
  //1. 빈 배열 result라는 방을 만듬
  //2. 요소들이 있는 arr이랑 result를 비교할 거임
  //3. indexOf는 해당 요소의 인덱스 번호를 반환하는데 없으면 -1을 반환
  //4. 빈 배열에 arr요소를 하나씩 넣음(-1이면 넣음, -1이 아니면 이미 있다는 뜻)
  //5. 값이 같은 요소는 인덱스 번호가 작은 수만 리턴한다는 indexOf 특징으로 중복 거르기 가능
  
    if(_.indexOf(result,el) === -1){
      result.push(el);
    }
  });
  return result;
};

 

 

map

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

_.map = function (arr, iteratee) {

  let result = [];
  _.each(arr, function (el) {
      result.push(iteratee(el));

  });
  return result; 
};

 

 

pluck

- _.pluck는 

- 1. 객체 또는 배열을 요소 갖는 배열과 각 요소에서 찾고자 하는 key또는 index를 입력 받아

- 2. 각 요소의 해당 값 또는 요소만을 추출하여 새로운 배열에 저장해 리턴

_.pluck = function (arr, keyOrIdx) {
  //_.map(arr,함수) -> 함수에 arr 요소를 넣은 결과 값들이 출력 됨
  //_.map 함수 자체를 요소를 순회할 수 있도록 구현해 놓았음
  //두 번째 인자로 넣은 함수를 key나 index에 맞는 값을 추출하는 함수로 만들면 됨
  
  let result = [];
  _.map(arr,function(el){
    result.push(el[keyOrIdx]);
  });
  
  return result;
};

 

 

reduce 

- _.reduce는

- 1. 배열을 순회하며 각 요소에 iteratee함수(acc, ele, idx, arr) 를 적용하고,

- 2. 그 결과값을 계속 누적(accumulate)함

- 3. 최종적으로 누적된 결과값 리턴

 

- 리듀서 함수의 4가지 인자

- 1. 누산기(acc)

- 2. 현재값(cur)

- 3. 현재 인덱스(idx) : 현재 처리할 요소의 인덱스. initialValue를 적용한 경우 0, 아니면 1부터 시작

- 4. 원본 배열(src) : 리듀서 호출 배열

 

- reduce()  작동 방식

arr.reduce(function(acc,cur,idx,arr){
  return acc + cur; // 누산식 예
}, initialValue);
_.reduce = function (arr, iteratee, initVal) {

  let acc = initVal;
  _.each(arr,function(el,idx,arr){
    
    if(acc === undefined){ //1.초기값을 제공하지 않으면 배열의 첫번째 요소 사용
      acc = arr[0];
    } else {
      acc = iteratee(acc, el, idx, arr); //2. 누산액에 할당 
    }
   });
  return acc;
};