[Javascript] Lodash 구현

Suh, Hyunwook·2021년 9월 12일
0
post-thumbnail

바닐라코딩 프렙 과정을 수강하면서 Underscore 과제를 통해 직접 메소드들을 구현해보니, 자바스크립트 내부 구조에 대해서 좀 더 명확히 이해할 수 있었다. Object, Array를 처리하는 방법 및 Higher-order function을 이해하기 위해서는 이만한 과제가 없는 듯하다.

부트캠프 어드미션을 대비하기 위해서라도, 추가적으로 Lodash를 구현해보기로 하였다.

_.chunk(array, [size=1]) : size에 맞는 덩어리로 배열을 분리해주는 메소드

Examples

_.chunk(['a', 'b', 'c', 'd'], 2);
// => [['a', 'b'], ['c', 'd']]
 
_.chunk(['a', 'b', 'c', 'd'], 3);
// => [['a', 'b', 'c'], ['d']]

Code

function chunk (collection, size) {
  // 예외처리 부분
  size = Math.max(parseInt(size), 0); // 음수일 경우 0, 양수일 경우 정수
  const length = collection === null ? 0 : collection.length; 
  
  if (!length || size < 1) return []; // 빈 배열이거나, size가 0일 때 빈 배열 return 
  
  // 구현 부분
  const result = new Array(Math.ceil(length / size));
  
   let index = 0;
   let resIndex = 0;
   while(index < length) {
     result[resIndex++] = collection.slice(index, index+size);
     index += size;
   }
   return result;
}

_.reduce(collection, iterator, accumulator) : collection의 각 element을 iterator에 적용하여 최종값을 return하는 메소드이며, 이 때 accumulator는 초기값임.

Examples

var sum = _.reduce([1, 2, 3], function(memo, num){ return memo + num; }, 0); // 6

Code

 _.reduce = function (collection, iterator, accumulator) {
    let tally;
    let newCollection;
    if (Array.isArray(collection)) {
      newCollection = [...collection];
    } else {
      newCollection = Object.values(collection);
    }

    if (accumulator === undefined) tally = newCollection.shift();
    else tally = accumulator;

    for (let i = 0; i < newCollection.length; i++) {
      tally = iterator(tally, newCollection[i]);
    }

    return tally;
  };

_.curry(func, [arity=func.length]) : arguments를 받고, func.length와 일치하면 func를 실행하고, arguments가 부족하면 함수를 return 하는 함수

Examples

var abc = function(a, b, c) {
  return [a, b, c];
};
var curried = _.curry(abc);
curried(1)(2)(3);
// => [1, 2, 3]

Code

// 첫번째 풀이 
function curry(fn) {
  const arity = fn.length; 
  const memory = [];
  return function resolver (...args) {
    for (let i = 0; i < args.length; i++) {
      memory.push(args[i]);
    }  
    if (memory.length === arity) {
      return fn.apply(this, memory);
    } else {
      return resolver;
    }
  }
}

// 두번째 풀이
function curry(fn) {
  const arity = fn.length;
  return function resolver() {
     const memory = Array.prototype.slice.call(arguments);
     return function () {
       const local = memory.slice();
       Array.prototype.push.apply(local, arguments);
       let next;
       if (local.length === arity) {
         next = fn;
       } else next = resolver;
        
       return next.apply(this, local);
     }
  }();
}

_.throttle(func, [wait=0], [options={}]) : 마지막 함수가 호출된 이후 일정 시간이 지나기 전에는 다시 호출되지 않도록 하는 메소드

Code

function throttle(func, delay) {
  let isCalled = true;
  return function (...args) {
    const context = this;
    if (isCalled) {
      func.apply(context, args);
      isCalled = false;
      
      setTimeout (() => {
        isCalled = true;
      },delay)
    }
  }
}

_.debounce(func, [wait=0], [options={}]) : 연이어 호출되는 함수들 중 마지막 함수만 호출되도록 하는 메소드

Code

function debounce(func, delay) {
  let timeoutId;
  return function (...args) {    
    if (timeoutId) {
      clearTimeout(timeoutId);
    }
    timeoutId = setTimeout(function () {
      func(...args);
    }, delay);
  }
}

_.contains(list, value, [fromIndex]) : valuelist에 존재할 경우 true를 반환하는 메소드

Examples

_.contains([1, 2, 3], 3); // true

Code

  _.contains = function (collection, target) {
    let newCollection;
    let result = false;
    if (Array.isArray(collection)) newCollection = collection;
    else newCollection = Object.values(collection);

    _.reduce(newCollection, function (memo, item) {
      if (item === target) result = true;
    }, 0)

    return result;
  };

_.memoize(function, [hashFunction]) : 이미 처리된 연산의 경우 cache에서 바로 return 하고, 연산되지 않은 부분만 추가로 연산하고, 추후 재사용을 위헤 cache에 메모하여, 결과적으로 속도, 성능을 재고하는 메소드

Examples

var fibonacci = _.memoize(function(n) {
  return n < 2 ? n: fibonacci(n - 1) + fibonacci(n - 2);
});

Code

  _.memoize = function (func) {
    const cache = {};
    return function () {
      const obj = JSON.stringify(arguments);
      if (!(cache.hasOwnProperty(obj))) {
        cache[obj] = func.apply(this, arguments);
      }
      return cache[obj];
    }
  };

_.concat(array, [values]) : array에 기타 array 또는 value를 합쳐 한 개의 array로 만들어주는 메소드

Examples

var array = [1];
var other = _.concat(array, 2, [3], [[4]]);
console.log(other);
// => [1, 2, 3, [4]]
console.log(array);
// => [1]

Code

function concat(array, ...args) {
  let result = [];
  for (let t = 0; t < array.length; t++) {
    result[t] = array[t];
  } // 깊은 복사를 위해서 위와 같이 설정 
  for (let i = 0; i < args.length; i++) { 
    if (Array.isArray(args[i])) {
      for (let j = 0; j< args[i].length; j++) {
        result.push(args[i][j]);
      }
    } else {
        result.push(args[i]);
    }
  }
  return result;
}

_.fill(array, value, [start=0], [end=array.length]) : 인자로 받은 value값을 처음부터 끝까지 array에 override하는 메소드

Examples

var array = [1, 2, 3];
 
_.fill(array, 'a');
console.log(array);
// => ['a', 'a', 'a']
 
_.fill(Array(3), 2);
// => [2, 2, 2]
 
_.fill([4, 6, 8, 10], '*', 1, 3);
// => [4, '*', '*', 10]

Code

function fill (array, value, start = 0, end = array.length) {
  
  const newArray = array;
  let filled = [];
  let length; 
  
  if (start || end) {
      length = end - start;
  }
  
  for (let i = 0; i < length; i++) {
    filled.push(value);
  }
  
  newArray.splice(start, length);
  newArray.splice(start,0,...filled);
  return newArray;
}

_.merge(object, [sources]) : objectother를 병합하는 메소드로서, object에 key가 있을 경우, 해당 key의 value 값을 override 하고, key가 없을 경우, object에 key를 추가하여 병합하는 메소드

Examples

var object = {
  'a': [{ 'b': 2 }, { 'd': 4 }]
};
 
var other = {
  'a': [{ 'c': 3 }, { 'e': 5 }]
};
 
_.merge(object, other);
// => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }

Code

function merge(object, other) {
  for (let key in other) {
    if (object.hasOwnProperty(key)) {
      for (let i = 0; i < other[key].length; i++) {
        Object.assign(object[key][i], other[key][i]);
        // assgin 메소드 : 자바스크립트 기본 내장 메소드로 객체를 합침 
      }
    } else {
      object[key] = other[key];
    } 
  }
  return object;
}

0개의 댓글