TIL07, JS: for, forEach, map, reduce, find, filter 정리*

sunghoonKim·2020년 11월 23일
5

for, forEach 등 서로 비슷해 보이는 메소드가 너무 많아 뇌에 괴부하가 왔다. 한번 정리하고 가겠다.

for 와 forEach 차이점

js에는 배열을 순회하는 방법으로 for 문과 forEach 를 사용하는 방법이 있다.

const arr = [1,2,3,4];

for (let i=0; i<arr.length; i++) {
  console.log(arr[i]);
}

arr.forEach(arrElement => console.log(arrElement));

문법적 차이를 설명하자면, for 문은 인덱스값에 해당하는 변수를 만들고, 그 변수의 값을 증가시키면서, 배열의 각 요소에 직접 접근하는 것이라면, forEach 문은 콜백 함수를 인자로 받아, 각각의 배열요소에 그 함수를 행하는 것이다.

기능적 측면만 고려한다면, 두가지 방법에 차이는 없다.


forEach(), map(), reduce(), find(), filter()의 각 사용처

forEach() 와 같은 배열 메소드가 여럿 존재하는데, forEach(), map(), reduce(), find(), filter() 가 그것이다. 문법적 차이도 없고, 기능적으로도 그 차이가 매우 크지는 않아서, 얼핏 보면 비슷한 메소드들 처럼 보인다. 따라서 그 차이점에 대해서 정리해보려 한다.

forEach()

const array1 = ['a', 'b', 'c'];

array1.forEach(element => console.log(element));
// expected output: "a"
// expected output: "b"
// expected output: "c"

콜백 함수를 인자로 받아, 배열의 각 요소에 콜백함수를 실행한다. 아무 값도 반환하지 않는다.

map()

const array1 = [1, 4, 9, 16];

const map1 = array1.map(x => x * 2);

console.log(map1); // expected output: Array [2, 8, 18, 32]

기존의 배열을 이용해, 새로운 배열을 생성할 때 사용한다. 콜백 함수를 인자로 받아, 배열의 각 요소에 대해서 실행한 결과 값을 반환한다.

(만약 생성된 새로운 배열을 변수에 저장하지 않으면 그 정보는 훨훨 날아가 없어진다. 즉, 기존의 배열을 수정하는게 아님.)

reduce()

// Syntax 예재
const newArr = arr.reduce(<reducerFunction>, initVal);
function reducerFunction (acc, crr, idx, src) {
  return acc + crr; 
}
// 실예재
const array1 = [1, 2, 3, 4];
const reducer = (accumulator, currentValue) => accumulator + currentValue;

console.log(array1.reduce(reducer)); // 1 + 2 + 3 + 4, expected output: 10
console.log(array1.reduce(reducer, 5)); // 5 + 1 + 2 + 3 + 4, expected output: 15

배열을 사용해서 일련의 행동을 취한 후 그 결과로 파생되는 하나의 값을 리턴할 때 사용한다. Syntax가 조금 특별한데, 각 배열에 적용할 reducer 함수와 리듀서 함수에서 사용될 initVal 초기값을 인자로 받는다.

reducer 함수는 4가지의 인자를 (acc: 누적값, crr: 현재값, idx: 현재값의 인덱스, src: 원본배열) 받는다. accinitVal 을 초기값으로 받는다. initVal 이 주어지지 않으면 배열의 첫번째 요소가 acc 의 값으로 결정된다. 함수에서 반환되는 값이 acc에 저장되어, 다음 배열에 대해서 reducer 함수가 다시 한번 진행될 때 사용된다. crracc 의 다음 배열 값을 받는다. idx 에는 crr 의 인덱스 값이, src 에는 원본배열이 저장된다.

리듀스 메소드는 배열 요소에 리듀서 함수를 적용하고, 결과적으로 마지막의 acc 의 값을 반환한다. 따라서, 예제 코드에서 사용된 리듀서 함수는 배열의 총합을 반환한다.

find()

const inventory = [
  {name: 'apples', quantity: 2},
  {name: 'bananas', quantity: 0},
  {name: 'cherries', quantity: 5}
];

function isCherries(fruit) { 
  return fruit.name === 'cherries';
}

console.log(inventory.find(isCherries)); // { name: 'cherries', quantity: 5 }

배열에서 하나의 요소를 선택할 때 사용한다. 이 메소드는 특정한 조건을 확인하는 함수를 인자로 받아, 조건을 만족하는 맨 처음 요소를 반환한다. 따라서, 인자에 넘겨지는 함수는 true 혹은 false 를 반환하여야 한다.

filter()

const words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];

const result = words.filter(word => word.length > 6);

console.log(result); // expected output: Array ["exuberant", "destruction", "present"]

배열에서 특정조건에 해당하는 여러 요소를 선택할때 사용한다. find 메소드와 동일하게 boolean 값을 반환하는 함수를 인자로 받는다.


정리하자면,
1. 반환값 없이 각 요소 값에 대해서 일련의 action을 취하려면, forEach를,
2. 새로운 배열을 생성하려면, map 을,
3. 하나의 결과 값을 반환하려면, reduce 를,
4. 하나의 요소를 선택하려면, find 를,
5. 특정 조건을 만족하는 여러개의 요소를 선택하려면, filter 을 쓴다.

성능적 측면에서 for 문이 forEach 문 보다 빠르지만, (forEach 가 나머지 배열 메소드보다 빠르고) for 문은 스코프를 오염시킬 수도 있는 가능성을 내제하는데 반해, forEach 문은 (그리고 아래에서 소개할 함수들은) 콜백함수를 불러 그 함수 스코프내에서 액션을 취하는 것이므로 스코프 오염의 문제에서 비교적 자유롭다.

따라서 항상 100퍼센트 옳은 방법은 없으니, 때에 따라 알맞은 방법을 선택할 수 있도록 하자. 👍

1개의 댓글

comment-user-thumbnail
2020년 11월 29일

잘 읽었습니다. 감사합니다 :)

답글 달기