js

Js - array method

존태 2022. 8. 28. 20:43

앞으로 많이 사용할 메서드 위주로 정리할 것이다.

 

foreach

arr.forEach는 주어진 함수를 배열 요소 각각에 대해 실행할 수 있게 해줍니다.

문법:

arr.forEach(function(item, index, array) {
  // 요소에 무언가를 할 수 있습니다.
});

아래는 요소 모두를 얼럿창을 통해 출력해주는 코드입니다.

 
 
// for each element call alert
["Bilbo", "Gandalf", "Nazgul"].forEach(alert);

아래는 인덱스 정보까지 더해서 출력해주는 좀 더 정교한 코드입니다.

 
 
["Bilbo", "Gandalf", "Nazgul"].forEach((item, index, array) => {
  alert(`${item} is at index ${index} in ${array}`);
});

참고로, 인수로 넘겨준 함수의 반환값은 무시됩니다.

 

filter

find 메서드는 함수의 반환 값을 true로 만드는 단 하나의 요소를 찾습니다.

조건을 충족하는 요소가 여러 개라면 arr.filter(fn)를 사용하면 됩니다.

filter는 find와 문법이 유사하지만, 조건에 맞는 요소 전체를 담은 배열을 반환한다는 점에서 차이가 있습니다.

let results = arr.filter(function(item, index, array) {
  // 조건을 충족하는 요소는 results에 순차적으로 더해집니다.
  // 조건을 충족하는 요소가 하나도 없으면 빈 배열이 반환됩니다.
});

예시:

 
 
let users = [
  {id: 1, name: "John"},
  {id: 2, name: "Pete"},
  {id: 3, name: "Mary"}
];

// 앞쪽 사용자 두 명을 반환합니다.
let someUsers = users.filter(item => item.id < 3);

alert(someUsers.length); // 2

map

arr.map은 유용성과 사용 빈도가 아주 높은 메서드 중 하나입니다.

map은 배열 요소 전체를 대상으로 함수를 호출하고, 함수 호출 결과를 배열로 반환해줍니다.

문법:

let result = arr.map(function(item, index, array) {
  // 요소 대신 새로운 값을 반환합니다.
});

아래 예시에선 각 요소(문자열)의 길이를 출력해줍니다.

 
 
let lengths = ["Bilbo", "Gandalf", "Nazgul"].map(item => item.length);
alert(lengths); // 5,7,6

reduce와 reduceRight

forEach, for, for..of를 사용하면 배열 내 요소를 대상으로 반복 작업을 할 수 있습니다.

각 요소를 돌면서 반복 작업을 수행하고, 작업 결과물을 새로운 배열 형태로 얻으려면 map을 사용하면 되죠.

arr.reduce와 arr.reduceRight도 이런 메서드들과 유사한 작업을 해줍니다. 그런데 사용법이 조금 복잡합니다. reduce와 reduceRight는 배열을 기반으로 값 하나를 도출할 때 사용됩니다.

문법:

let value = arr.reduce(function(accumulator, item, index, array) {
  // ...
}, [initial]);

인수로 넘겨주는 함수는 배열의 모든 요소를 대상으로 차례차례 적용되는데, 적용 결과는 다음 함수 호출 시 사용됩니다.

함수의 인수는 다음과 같습니다.

  • accumulator – 이전 함수 호출의 결과. initial은 함수 최초 호출 시 사용되는 초깃값을 나타냄(옵션)
  • item – 현재 배열 요소
  • index – 요소의 위치
  • array – 배열

이전 함수 호출 결과는 다음 함수를 호출할 때 첫 번째 인수(previousValue)로 사용됩니다.

첫 번째 인수는 앞서 호출했던 함수들의 결과가 누적되어 저장되는 '누산기(accumulator)'라고 생각하면 됩니다. 마지막 함수까지 호출되면 이 값은 reduce의 반환 값이 됩니다.

복잡해 보이긴 하지만 예제를 통해 메서드를 이해해 봅시다.

reduce를 이용해 코드 한 줄로 배열의 모든 요소를 더한 값을 구해보겠습니다.

 
 
let arr = [1, 2, 3, 4, 5];

let result = arr.reduce((sum, current) => sum + current, 0);

alert(result); // 15

reduce에 전달한 함수는 오직 인수 두 개만 받고 있습니다. 대개 이렇게 인수를 두 개만 받습니다.

이제 어떤 과정을 거쳐 위와 같은 결과가 나왔는지 자세히 살펴보겠습니다.

  1. 함수 최초 호출 시, reduce의 마지막 인수인 0(초깃값)이 sum에 할당됩니다. current엔 배열의 첫 번째 요소인 1이 할당됩니다. 따라서 함수의 결과는 1이 됩니다.
  2. 두 번째 호출 시, sum = 1 이고 여기에 배열의 두 번째 요소(2)가 더해지므로 결과는 3이 됩니다.
  3. 세 번째 호출 시, sum = 3 이고 여기에 배열의 다음 요소가 더해집니다. 이런 과정이 계속 이어집니다.

계산 흐름:

 

표를 이용해 설명하면 아래와 같습니다. 함수가 호출될 때마다 넘겨지는 인수와 연산 결과는 각 열에서 확인할 수 있습니다.

sumcurrentresult

첫 번째 호출 0 1 1
두 번째 호출 1 2 3
세 번째 호출 3 3 6
네 번째 호출 6 4 10
다섯번째 호출 10 5 15

이제 이전 호출의 결과가 어떻게 다음 호출의 첫 번째 인수로 전달되는지 아셨죠?

한편, 아래와 같이 초깃값을 생략하는 것도 가능합니다.

 
 
let arr = [1, 2, 3, 4, 5];

// reduce에서 초깃값을 제거함(0이 없음)
let result = arr.reduce((sum, current) => sum + current);

alert( result ); // 15

초깃값을 없애도 결과는 동일하네요. 초깃값이 없으면 reduce는 배열의 첫 번째 요소를 초깃값으로 사용하고 두 번째 요소부터 함수를 호출하기 때문입니다.

위 표에서 첫 번째 호출에 관련된 줄만 없애면 초깃값 없이 계산한 위 예제의 계산 흐름이 됩니다.

하지만 이렇게 초깃값 없이 reduce를 사용할 땐 극도의 주의를 기울여야 합니다. 배열이 비어있는 상태면 reduce 호출 시 에러가 발생하기 때문입니다.

예시:

 
 
let arr = [];

// TypeError: Reduce of empty array with no initial value
// 초깃값을 설정해 주었다면 초깃값이 반환되었을 겁니다.
arr.reduce((sum, current) => sum + current);

이런 예외상황 때문에 항상 초깃값을 명시해 줄 것을 권장합니다.

arr.reduceRight는 reduce와 동일한 기능을 하지만 배열의 오른쪽부터 연산을 수행한다는 점이 다른 메서드입니다.