Js - array method
앞으로 많이 사용할 메서드 위주로 정리할 것이다.
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에 전달한 함수는 오직 인수 두 개만 받고 있습니다. 대개 이렇게 인수를 두 개만 받습니다.
이제 어떤 과정을 거쳐 위와 같은 결과가 나왔는지 자세히 살펴보겠습니다.
- 함수 최초 호출 시, reduce의 마지막 인수인 0(초깃값)이 sum에 할당됩니다. current엔 배열의 첫 번째 요소인 1이 할당됩니다. 따라서 함수의 결과는 1이 됩니다.
- 두 번째 호출 시, sum = 1 이고 여기에 배열의 두 번째 요소(2)가 더해지므로 결과는 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와 동일한 기능을 하지만 배열의 오른쪽부터 연산을 수행한다는 점이 다른 메서드입니다.