2 minute read

우리가 현재 아주 편리하게 사용하는 배열 Method들이 내장 Method가 아닌 시절이 있었다.

ex) filter(), map(), reduce(), indexOf(), each()

이런 Method들을 사용할 때마다 작성해주는것이 너무 비효율적이라,

underscore.js, lodash등을 구축해 Method 라이브러리를 만들었다.

한마디로, 치트키를 만든 것이다.

만약에, 내장 Method가 존재하지 않고, map의 동작을 이용하고 싶다면 아래와 같은 코드를 작성해야 한다.

const map = function (arr, callback) {
  let result = [];
  for (let i = 0; i < arr.length; i++) {
    result.push(callback(arr[i]))
  }
  return result;
}

const add1 = (num) => num + 1;
const multyple2 = (num) => num * 2;

console.log(map([1, 2, 3], add1)); // [2, 3, 4]
console.log(map([1, 2, 3], multyple2)); // [2, 4, 6]

하지만, 내장 Method가 존재할땐 아래와 같이 아주 간단하게 동작을 시킬 수 있다.

[1, 2, 3].map((num) => num + 1); // [2, 3, 4]
[1, 2, 3].map((num) => num * 2); // [2, 4, 6]

무려 단 1줄만에 가능하다!!

그럼, 우리가 평소 당연하게 사용했던 내장 Method들이 내부에선 어떻게 작동하는지 몇가지 알아보면서

고차함수와 callback에 익숙해지는 시간을 가져보자.

우선, collection(배열 또는 객체) 과 iteratee(반복되는 작업) 를 인자로 전달받아 collection의 데이터를 순회하면서, iteratee에 각 데이터를 인자로 전달하여 실행하는 함수를 만들어준다.

// collection은 배열 또는 객체, iteratee는 데이터, 접근자, collection
each = function (collection, iteratee) {
// 만약 collection이 배열이라면,
  if (Array.isArray(collection)) {
// 0부터 collecion의 길이만큼 돌며, iteratee에 각각 데이터, 접근자, collection을 인자로 넘긴다)
    for (let i = 0; i < collection.length; i++) {
      iteratee(collection[i], i, collection);
    }
// 만약 collection이 객체라면,
  } else {
// collection의 key들을 선언된 key에 계속 넣으며, 
//iteratee에 데이터, 접근자, collection을 인자로 넘긴다.
    for (let key in collection) {
      iteratee(collection[i], i, collection);
    }
  }
};

.filter() Method

filter = function (arr, test) {
// 배열 Method인 filter는 조건에 맞는 요소를 가진 배열을 리턴해야하기 때문에, 빈배열을 선언한뒤 넣어주자
  let result = [];
// 위에서 작성해놓은 each함수를 이용해 배열과 각 조건이 작성돼있는 함수 test를 실행해 true이면
// result에 push해주는 함수를 인자로 넣어준다.
  each(arr, function(item) {
    if (test(item)) result.push(item);
  });
  return result;
};

const arr = [1, 2, 3, 4, 5];
const isEven = (num) => num % 2 === 0;
const over5 = (num) => num >= 5;

console.log(filter(arr, isEven)); // [2, 4]
console.log(filter(arr, over5)); // [5]

내장 Method를 사용한다면?

const arr = [1, 2, 3, 4, 5];
arr.filter(num => num % 2 === 0) // [2, 4]
arr.filter(num => num >= 5) // [5]

.reduce() Method

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

	each(arr, function (item, idx, src) {
	  if (initVal === undefined && idx === 0) {
	    acc = item;
	  } else {
	    acc = iteratee(acc, item, idx, src);
	  }
	})
	return acc;
};

const addAll = (acc, item) => acc + item;
const multypleAll = (acc, item) => acc * item;

reduce([1, 2, 3, 4, 5], addAll) // 15
reduce([1, 2, 3, 4, 5], addAll, 5) // 20
reduce([1, 2, 3, 4, 5], multypleAll) // 120
reduce([1, 2, 3, 4, 5], multypleAll, 2) // 240

내장 Method를 사용한다면?

const arr = [1, 2, 3, 4, 5];
arr.reduce((acc, cur) => acc + cur) // 15
arr.reduce((acc, cur) => acc + cur, 5) // 20
arr.reduce((acc, cur) => acc * cur) // 120
arr.reduce((acc, cur) => acc * cur, 2) // 240

Updated: