forEach, map, filter, reduce


:raising_hand: JavaScript 문법 내용을 기록하기 위한 포스트입니다.


forEach, map, filter, reduce 네개의 메서드에 관해서 간략하게 기록한다.

4개의 메서드는 모두 함수값을 전달 받는 고차함수이다.

1. foreach


forEach 문은 배열에 접근할 때 for 반복문 대신 접근할 수 있는 내장 메서드 이다.

let a = [10, 11, 12, 13, 14, 15];
a.forEach(
  function (v, i) {
    console.log(v, i, this);
  },
  [1, 2]
);

위 코드를 돌려보면

image

여기서 forEach 의 결과를 보면 a 배열의 값과 인덱스 값, 매개변수로 준 값이 차례로 호출되는 것을 볼 수 있다.

우리가 사용하는 경우에는 주어진 배열값을 특정 CallBack Function 에 전달하려 실행하는 경우이고 추가적인 매개변수를 통해 추가 정보를 사용할수 있다는 점을 기억하면 될 것 같다

즉, 결과적으로만 보았을때는 아래와 같이 동작한다고 생각하면 될 것 같다.

function forEach(predicate, thisArg) {
  for (let i = 0; i < a.length; i++) {
    predicate(a[i], i, thisArg);
  }
}

forEach 는 함수를 매개변수에 포함해서 받게 되므로 CallBack 함수가 들어가게 되고 내부에서 a 배열 값을 차례로 해당 함수에 넣어주는 방식인 것 같다.

v 에는 a 배열의 값이 들어갔고 i 에는 해당 값의 인덱스 그리고 매개변수가 출력되었다.

위 forEach 코드의 경우에는 실제 내부 함수가 아닌 대략적인 나의 생각을 코드로 정리해본 것이다.

2. Map


맵의 경우 아래와 같이 동작한다고 유추 할 수 있다.

function map(predicate, thisArg) {
  let list = [];
  for (let i = 0; i < a.length; i++) {
    list.push(predicate(a[i], i));
  }
}

아래와 같이 내장함수를 사용하여 콘솔을 찍어보면

let a = [10, 11, 12, 13, 14, 15];
let answer = a.map(function (v, i) {
  return v * v;
});
console.log(answer);

image

위와 같은 결과를 얻을 수 있다.

map 에 function(v, i) 에는 a 의 원소 10 ~ 15 와 각 index 가 들어가게 되고 결과값으로 v * v 가 리턴된다.

리턴된 값은 list 에 담겨져 최종 리턴되게 된다.

let answer = a.map(function (v, i) {
  if (v % 2 == 0) {
    return v * v;
  }
});
console.log(answer);

추가적으로 알아야할 점이 만약 아래와 같이 조건별로 return 을 했다면 조건에 맞는 값만 최종 리턴배열에 들어갈까?

답은 “아니오” 이다.

Map의 경우 a 리스트 를 받아와 조건을 걸든 안걸든 function 을 a 의 length 만큼 실행하고 내부 list 에 push 하기 때문에

만약 조건에 안맞는 결과이더라도 undefined 로 추가 되게 된다. 따라서 원본 배열과 같은 길이가 같은 배열을 리턴한다.

이점 유의가 필요하다.

image

3. filter


위 Map 에서는 어쩔 수 없이 input 된 모든 요소가 어떠한 형태로든 배열에 추가되어 return 되는것을 알아봤다.

만약 원하는 조건의 요소만 리턴받고 싶을 경우 filter 를 사용하면 될 것이다. filter 는 Map 과 비슷하다고 생각하면 되나 원하는 요소만 뽑아서 리턴해준다.

let a = [10, 11, 12, 13, 14, 15];
let answer = a.filter(function (v, i) {
  if (v % 2 == 0) {
    return v * v;
  }
});
console.log(answer);

위 코드를 실행시켜보면 v%2 == 0 조건에 맞는 요쇼들만 return 되게 된다.

image

추가적으로 알 수 있는 부분은 return 에 조건을 명시하면 조건에 맞는 값만 리턴하게 된다.

memList = memList.filter(function (item) {
  return item !== max;
});

따라서 동작을 추측하여 코드로 보면 아래와 같이 구현할 수 있을 것 같다.

function filter(predicate, thisArg) {
  let list = [];
  for (let i = 0; i < a.length; i++) {
    if (predicate(a[i], i)) {
      list.push(a[i]);
    }
  }
}

4.reduce


reduce 가 기본적으로 동작하는 방식을 나름의 생각으로 코드화 해보았다.

function reduce(predicate, val) {
  let result = val;
  for (let i = 0; i < a.length; i++) {
    result = predicate(result, a[i]);
  }
  return result;
}

위 방식으로 내장함수가 돌아가게 되고

let a = [10, 11, 12, 13, 14, 15];
let answer = a.reduce(function (acc, v) {
  return acc + v;
}, 0);
console.log(answer);

위 로직으로 설명을 남긴다.

먼저 reduce 는 앞서 설명한 다른 3개와는 조금 다르게 복잡하게 돌아간다.

reduce파라메터function초기값을 보내게 된다.

위 예제에선 초기값으로 0을 보냈으므로 처음 result 값은 0으로 선언이 되고 반복문으로 들어가 result 값첫번째 파라메터 function 에 0으로 선언된 result값, a 배열의 값 이 매개변수로 들어가게된다.

그럼 예제에서는 callback 함수return첫번째 두번째 매개변수의 합을 리턴하므로 0 + a0 = 10 이 리턴된다.

그러면 result 는 10이되고 다시 반복문이 돌게될때에는 callback 함수에 10, 11 이 매개변수로 들어가 10 + a1 = 21 이 리턴된다.

결과적으로 reduce 는 callback 함수의 return 값이 첫번째 매개변수에 전달되는것, 2번째 인자는 초기값 인것만 알면 좋을것 같다.

보통 합을 구할때 주로 사용하는 편이다.

참조 사이트


MDN 사이트 https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/filter