Skip to content
This page has been auto-translated and may contain errors.View in English

배열 메서드

docs.scrimba.com

가격 목록이 있고 각각에 세금이 추가된 두 번째 목록을 원한다고 하겠습니다. 배열을 순회하고 합계를 구한 다음 각 결과를 새 배열에 푸시하는 for 루프를 작성할 수 있습니다. 그것도 작동하지만, 작은 아이디어를 위한 많은 배선입니다: 모든 항목을 가져와서 변경합니다. 배열 메서드는 정확히 이런 종류의 작업을 위한 내장 도구입니다. 루프를 상세히 설명하지 않고도 리스트에 대해 원하는 것을 말할 수 있으며, 이 장에서는 매일 사용할 메서드들을 다룹니다. 이들은 배열함수를 직접 기반으로 하므로 두 가지 모두 가까이 두세요.

map: 모든 항목 변경

map메서드: 배열에 속하고 배열에 작업을 수행하는 함수입니다. map은 각 항목을 제공한 작은 함수를 통해 실행하고 결과를 수집하여 새 배열을 만듭니다. 해당 함수를 전달하면 각 항목을 한 번에 하나씩 전달합니다.

일부 가격이 있고 각각을 두 배로 늘리고 싶다고 하겠습니다:

js
const prices = [2, 4, 6];
const doubled = prices.map((price) => price * 2);
console.log(doubled); // [4, 8, 12]

(price) => price * 2 부분은 화살표 함수: 한 항목(price)을 가져와서 그것이 무엇이 되어야 하는지(price * 2)를 반환하는 짧은 함수입니다. map은 각 항목마다 한 번씩 호출하고 각 답을 같은 순서로 새 배열에 넣습니다.

map은 배열 **메서드**로 리스트를 같은 길이의 새 리스트로 변환합니다. 콜백(함수를 제공해서 map이 항목마다 한 번씩 실행)을 제공하면, 그 콜백이 반환하는 것이 결과의 같은 위치에 있는 항목이 됩니다.

js
const prices = [2, 4, 6];
const doubled = prices.map((price) => price * 2);
console.log(doubled); // [4, 8, 12]

같은 작업을 하지만 더 많은 움직이는 부분을 가진 수동 버전과 비교해봅시다:

js
const prices = [2, 4, 6];
const doubled = [];
for (let i = 0; i < prices.length; i += 1) {
  doubled.push(prices[i] * 2);
}
console.log(doubled); // [4, 8, 12]

루프는 인덱스, 새 배열, push를 관리해야 합니다. map은 의도를 명시합니다, "각 가격을 가격의 2배로 변환", 그리고 나머지 세부사항을 처리합니다.

map은 배열을 콜백(호출하기 위해 전달하는 함수)을 각 요소에 적용하여 같은 길이의 새 배열로 변환합니다. 인덱스 i에서 콜백의 반환 값이 결과의 인덱스 i의 요소가 됩니다. 아무것도 건너뛰거나 추가되지 않으므로 모양은 보존되고 값만 변경됩니다.

js
const prices = [2, 4, 6];
const withTax = prices.map((price) => price * 1.2);
console.log(withTax); // [2.4, 4.8, 7.2]

콜백은 또한 위치가 중요할 때를 위해 두 번째 및 세 번째 인수로 인덱스와 전체 배열을 받으므로 array.map((value, index) => ...) 형태가 가능합니다. 이것이 보유하는 값의 의도입니다: map은 "같은 길이, 각 항목 변환"이라고 한눈에 말합니다, 루프는 인덱스, 카운터, push에서 재구성하게 합니다.

Junomapmap은 리스트를 가져와서 같은 길이의 새 리스트를 제공하며, 모든 항목이 작은 함수를 통해 실행됩니다. 화살표 함수는 각 항목이 무엇으로 변환되는지를 말하고, map은 모두를 순서대로 수행합니다. 두 번째 리스트를 만들기 위해서만 루프를 작성하는 것을 잡을 때마다 이를 사용합니다.
Junomapmap은 "모든 항목을 같은 길이의 새 배열로 변환"합니다. 콜백은 항목마다 한 번씩 실행되고 반환 값이 같은 위치에 들어갑니다. 루프 플러스 푸시 패턴의 대체로 본다면, 루프의 절반이 단일 읽기 쉬운 라인으로 변환됩니다.
Junomapmap은 길이와 위치를 보존합니다: 인덱스 i에서 콜백의 반환이 결과의 인덱스 i가 됩니다. 콜백은 위치가 중요할 때를 위해 인덱스와 배열도 받습니다. 루프에서 카운터와 push에서 재구성하게 하는 것과 달리 의도로 읽힙니다.

filter: 통과하는 항목 유지

map이 모든 항목을 변경하는 경우, filter는 일부만 유지합니다. 각 항목에 대해 예 또는 아니오로 답하는 함수를 제공하면, filter는 예를 받은 항목들로만 새 배열을 만듭니다.

js
const scores = [40, 75, 90, 55, 88];
const passing = scores.filter((score) => score >= 60);
console.log(passing); // [75, 90, 88]

함수 (score) => score >= 60은 각 점수에 대해 true 또는 false를 반환합니다. filtertrue인 것들을 유지하고 나머지는 삭제합니다. 새 배열은 원래 배열보다 짧을 수 있으며, 순서를 변경하지 않습니다.

filter는 콜백이 true를 반환하는 항목만 보유하는 새 배열을 반환합니다. 콜백은 술어: 각 항목에 대해 예 또는 아니오 질문에 답하는 것이 목표인 함수입니다.

js
const scores = [40, 75, 90, 55, 88];
const passing = scores.filter((score) => score >= 60);
console.log(passing); // [75, 90, 88]

결과는 종종 입력보다 짧고, 원래 순서를 유지합니다. 내부에 if가 있는 루프와 비교하면, filter는 테스트를 맨 앞에 두고 주변 형식을 제거합니다. 콜백이 모든 항목에 대해 true를 반환하면 전체 복사본을 받습니다. 모든 항목에 대해 false를 반환하면 빈 배열을 받습니다.

filter술어(트루시 또는 팰시 답변을 반환하는 것이 목표인 콜백) 항목들의 새 배열을 반환합니다. 길이는 보존되지 않습니다: 결과는 비워진 상태에서 전체 복사본까지 실행되며, 순서는 유지됩니다.

js
const scores = [40, 75, 90, 55, 88];
const passing = scores.filter((score) => score >= 60);
console.log(passing); // [75, 90, 88]

명확히 유지할 가치가 있는 두 가지가 있습니다. 첫째, filter는 항목의 생존 여부를 결정합니다. 절대 항목을 변경하지 않으므로 선택과 변환을 모두 해야 할 때 map과 결합합니다. 둘째, 콜백의 반환은 부울로 강제됩니다. 따라서 실수로 0 또는 undefined를 반환하는 술어는 유지하려던 항목을 삭제합니다. 명시적 비교를 반환하면 버그의 이 클래스가 사라집니다.

Junofilterfilter는 테스트를 통과하는 항목을 유지하고 나머지는 제거하므로 새 배열은 종종 짧습니다. 함수는 각 항목에 대해 예 또는 아니오로 답하고 예만 통과합니다. 아무것도 순서를 변경하지 않으므로 생존하는 것은 시작한 순서로 유지됩니다.
Junofilterfilter는 콜백이 true를 반환하는 항목을 유지하여 같은 길이 또는 더 짧은 새 배열을 제공합니다. 콜백은 술어입니다: 변환기가 아닌 예 또는 아니오 테스트입니다. 모든 true는 전체 복사본을 제공하고, 모든 false는 빈 배열을 제공하며, 순서는 항상 보존됩니다.
Junofilterfilter는 선택하고 map은 변환하며, 그 분할을 깔끔하게 유지하는 것이 왜 그들이 잘 연결되는지입니다. 콜백의 반환은 부울로 강제되므로 0 또는 undefined를 몰래 내보내는 술어는 원하던 항목을 조용히 삭제합니다. 명시적 비교를 반환하면 버그의 전체 클래스가 사라집니다.

reduce: 한 값으로 축약

mapfilter는 모두 배열을 반환합니다. reduce는 배열을 단일 값으로 축약하는 것입니다: 합계, 최댓값, 결합된 문자열입니다. 다른 것들보다 더 많이 사람들을 혼동시키므로 천천히 가는 것이 가치가 있습니다.

reduce는 배열을 순회하면서 실행 중인 결과를 함께 전달합니다. 각 항목에서 이렇게 묻습니다: 지금까지의 결과를 고려하고 이 항목을 고려했을 때, 새로운 결과는 무엇인가요?

js
const prices = [10, 20, 30];
const total = prices.reduce((sum, price) => sum + price, 0);
console.log(total); // 60

함수는 두 가지를 받습니다: sum, 지금까지의 실행 합계, price, 현재 항목입니다. sum + price를 반환하고, 이것이 다음 항목의 새로운 실행 합계가 됩니다. 끝의 0은 합계가 시작되는 곳입니다. 그래서 0 + 10을 계산한 다음 10 + 20, 그 다음 30 + 30으로 60에 도달합니다.

reduce누적값: 각 단계가 업데이트하고 전달하는 실행 중인 결과를 전달하여 전체 배열을 하나의 값으로 변환합니다. 콜백은 누적값과 현재 항목을 받고 다음 단계를 위한 누적값을 반환합니다.

js
const prices = [10, 20, 30];
const total = prices.reduce((sum, price) => sum + price, 0);
console.log(total); // 60

명확히 유지해야 할 두 가지 인수가 있습니다: sum은 누적값입니다(지금까지 구축된 값), price는 현재 항목입니다. reduce의 두 번째 인수인 0은 누적값의 시작 값입니다. 단계별로: 0에서 시작하여 10을 더하면 10, 20을 더하면 30, 30을 더하면 60. 이름 sum은 여기서만 레이블입니다. 누적값은 계속 추가하는 문자열이나 실행 중인 최댓값을 포함한 모든 유형이 될 수 있습니다.

reduce누적값(실행 중인 결과)을 배열을 통해 스레드 처리하여 배열을 단일 값으로 접습니다. 콜백은 (accumulator, currentItem) => nextAccumulator이고, 반환은 다음 단계로 전달되는 누적값이 됩니다. reduce의 두 번째 인수는 초기 누적값입니다.

js
const prices = [10, 20, 30];
const total = prices.reduce((sum, price) => sum + price, 0);
console.log(total); // 60

두 가지 실용적인 규칙이 대부분의 reduce 버그를 방지합니다. 항상 초기 값을 전달합니다: 없으면 reduce는 첫 번째 요소를 시드로 사용하고 두 번째부터 시작하므로 빈 배열에서 throw되고 누적값 유형이 요소 유형과 다를 때 동작이 조용히 변경됩니다. 그리고 콜백을 통한 모든 경로는 누적값을 반환해야 합니다; 다중 라인 본문에서 return을 빠뜨리면 다음 단계를 위한 누적값으로 undefined가 남겨집니다. reduce는 이러한 메서드 중 가장 일반적이고, mapfilter는 모두 reduce로 작성될 수 있습니다. 정확히 그렇기 때문에 읽기 어렵게 만들기도 가장 쉽습니다. 한 값으로 축약할 때 사용하고, 축약하지 않을 때는 더 간단한 것을 사용합니다.

Junoreducereduce는 리스트를 통해 실행 중인 결과를 전달하고 각 항목에서 업데이트합니다. 콜백은 지금까지의 결과와 현재 항목을 받고 새 결과를 반환합니다. 마지막 인수는 시작 위치이고 보통 합계는 0입니다. 단계별로 읽으면 바로 클릭되었습니다.
Junoreducereduce는 누적값을 사용하여 배열을 한 값으로 축약합니다: 각 단계가 업데이트하고 전달하는 실행 중인 결과입니다. 콜백은 (accumulator, item)이고 마지막 인수는 누적값을 시드합니다. 숫자일 필요는 없습니다. 누적값은 구축하는 문자열이나 실행 중인 최댓값이 될 수 있습니다.
Junoreduce 항상 초기 값을 전달합니다. 그렇지 않으면 reduce는 첫 번째 요소에서 시드하고 빈 배열에서 throw됩니다. 콜백을 통한 모든 경로는 누적값을 반환해야 합니다. 그렇지 않으면 다음 단계는 undefined를 받습니다. 이 메서드 중 가장 일반적이고 읽기 어렵게 만들기가 가장 쉬우므로 한 값으로 축약할 때 사용하고 축약하지 않을 때는 더 간단한 것을 사용합니다.

find, some, 그리고 every

이 셋은 filter의 가까운 상대입니다: 배열에 대한 테스트를 실행하지만, 새 배열 대신 더 좁은 질문에 답합니다.

find는 모든 항목의 리스트가 아니라 테스트를 통과하는 첫 번째 항목을 제공합니다. someevery는 전체 배열에 대해 참 또는 거짓 질문에 답합니다.

js
const scores = [40, 75, 90, 55];

const firstPass = scores.find((score) => score >= 60);
console.log(firstPass); // 75

const anyPass = scores.some((score) => score >= 60);
console.log(anyPass); // true

const allPass = scores.every((score) => score >= 60);
console.log(allPass); // false

find는 첫 번째 일치하는 항목(75)을 반환합니다. some은 "어떤 항목이 통과했나?"라고 묻고 최소한 하나가 통과했으므로 true를 반환합니다. every는 "모두 통과했나?"라고 묻고 4055가 통과하지 못했으므로 false를 반환합니다.

filter와 같은 술어 스타일, 세 가지 다른 답변입니다. find는 **첫 번째 일치하는 항목**을 반환합니다(일치하는 것이 없으면 undefined). some은 최소한 하나의 항목이 통과하면 true를 반환합니다. every는 모든 항목이 통과할 때만 true를 반환합니다.

js
const scores = [40, 75, 90, 55];

console.log(scores.find((score) => score >= 60)); // 75
console.log(scores.some((score) => score >= 60)); // true
console.log(scores.every((score) => score >= 60)); // false

필터링된 리스트가 아닌 하나의 항목을 원할 때 find를 사용하고, 컬렉션에 대한 예 또는 아니오 답변만 필요할 때 some 또는 every를 사용합니다. filter(...).length > 0some이 할 수 있는 곳에서 사용하는 것이 작동하지만, 모든 항목을 확인하고 some이 직접 답하는 질문에 답하기 위해 일회용 배열을 만듭니다.

새 배열을 만들지 않고 빨리 멈추는 세 가지 술어 기반 쿼리입니다. find첫 번째 일치하는 요소 또는 undefined를 반환합니다. some은 첫 번째 통과 요소에서 true를 반환합니다. every는 첫 번째 실패 요소에서 false를 반환합니다.

js
const scores = [40, 75, 90, 55];

console.log(scores.find((score) => score >= 60)); // 75
console.log(scores.some((score) => score >= 60)); // true
console.log(scores.every((score) => score >= 60)); // false

단락 계산이 요점입니다: someevery는 답이 결정된 순간 멈추므로, 부울만 필요할 때 전체 배열에 대한 filter 보다 비용이 낮습니다. 알아야 할 두 가지 엣지 경우가 있습니다: findundefined를 반환하는 것은 실제 undefined를 찾는 것과 구별할 수 없으므로 반환 값이 아닌 관심 있는 술어를 테스트합니다(가능할 때). 그리고 빈 배열에서 some은 항상 false이고 every는 항상 true입니다(부공허하게, 실패할 항목이 없으므로), 올바르지만 사람들은 처음에 놀랍니다.

Junofind, some, and everyfind는 전체 리스트가 아니라 통과하는 첫 번째 항목을 제공합니다. some은 "어떤 항목이 통과했나?"라고 묻고 every는 "모두 통과했나?"라고 묻습니다. 둘 다 true 또는 false로 답합니다. 필터링된 배열이 아니라 하나의 항목 또는 예 또는 아니오 답변을 원할 때 이들을 사용합니다.
Junofind, some, and everyfilter와 같은 술어, 세 가지 더 좁은 답변: find는 첫 번째 일치 또는 undefined를 제공하고, some은 어떤 항목이 통과하면 참이며, every는 모두 통과할 때만 참입니다. 하나의 항목이나 부울을 원할 때 filter(...).length 대신 이들을 사용합니다. 의도를 말하고 일회용 배열 구축을 건너뜁니다.
Junofind, some, and everysomeevery는 단락 계산하므로 답이 결정된 순간 멈추고 부울을 위해 전체 배열을 필터링하는 것을 이깁니다. 두 가지 엣지를 봅니다: findundefined를 반환하는 것은 실제 undefined를 찾는 것처럼 보이고, 빈 배열에서 some은 항상 거짓이고 every는 항상 참입니다. 둘 다 올바르고 둘 다 한 번 사람들을 놀라게 합니다.

연결 및 읽기 가능성 유지

위의 메서드들은 결합할 때 기여하는 설계를 공유합니다: 각각은 새 값을 반환하고 원래 배열은 건드리지 않습니다.

map, filter 등은 시작한 배열을 변경하지 않습니다. 새 배열(또는 값)을 제공하고 원본은 그대로 둡니다.

js
const prices = [10, 20, 30];
const doubled = prices.map((price) => price * 2);
console.log(doubled); // [20, 40, 60]
console.log(prices); // [10, 20, 30]

mapfilter 모두 배열을 반환하기 때문에 이들을 정렬할 수 있습니다: 먼저 필터링한 다음 생존자를 맵합니다.

js
const prices = [10, 20, 30, 40];
const bigDoubled = prices.filter((price) => price >= 20).map((price) => price * 2);
console.log(bigDoubled); // [40, 60, 80]

이 메서드들은 새 배열과 값을 반환하고 원본을 변경하지 않으며, 이를 **불변성**이라고 하는 속성입니다: 원본 데이터는 그대로 유지됩니다. 이것이 연결을 안전하게 만드는 것입니다. filter가 배열을 반환하기 때문에 결과에 바로 map을 호출할 수 있습니다:

js
const prices = [10, 20, 30, 40];
const bigDoubled = prices.filter((price) => price >= 20).map((price) => price * 2);
console.log(bigDoubled); // [40, 60, 80]

연결을 위에서 아래로 파이프라인으로 읽습니다: 20 이상의 가격을 유지한 다음 각 생존자를 두 배로 늘립니다. 순서가 중요합니다. filter 먼저는 map이 더 적은 항목으로 실행되기 때문입니다. 연결은 2 또는 3 단계까지 잘 읽히고; 그 이후 명명된 중간 변수나 일반 루프는 종종 하나의 긴 연결보다 읽기 더 명확합니다.

이 메서드들은 비변경하는 것입니다: 새 배열과 값을 반환하고 원본을 건드리지 않습니다. 그 **불변성**이 filter(...).map(...) 연결을 파이프라인으로 안전하게 읽을 수 있게 합니다. 어떤 단계도 뒤로 돌아가서 공유된 배열을 당신 아래에서 편집하지 않기 때문입니다.

js
const prices = [10, 20, 30, 40];
const bigDoubled = prices.filter((price) => price >= 20).map((price) => price * 2);
console.log(bigDoubled); // [40, 60, 80]

두 가지 판단 호출이 연결이 도움이 되는지 상처를 주는지 결정합니다. 첫째, 비용: 각 단계는 배열을 순회하고 새 것을 할당하므로 3단계 연결은 3번의 통과와 2개의 중간 배열을 만듭니다. 매일 만나는 크기에서 이것은 관계없고 읽기 쉬움이 이기므로; 큰 배열에 대한 핫 경로에서는 문제가 될 수 있으며 한 번의 통과로 작업을 수행하는 단일 루프나 reduce가 답입니다. 둘째, 명확성: 연결이 제 위치를 획득하면 각 단계가 하나의 명확한 아이디어입니다. 콜백이 분기가 있는 본문을 키우거나 연결이 3단계를 지나자마자 일반 for 루프가 잘 명명된 변수로 더 읽기 좋습니다. 가장 짧은 것이 아니라 팀원이 가장 빨리 이해하는 버전을 선호합니다.

JunoChaining and staying readable 이 메서드들은 시작한 배열을 변경하지 않고 새 것을 제공하므로 원본은 항상 안전합니다. filtermap이 모두 배열을 반환하기 때문에 이들을 연결할 수 있습니다: 먼저 필터링한 다음 남은 것을 맵합니다. 위에서 아래로, 한 번에 한 단계씩 연결을 읽습니다.
JunoChaining and staying readable 불변성, 원본 배열을 그대로 두는 것이 연결을 안전하게 만듭니다. filter(...).map(...)을 파이프라인으로 위에서 아래로 읽고, 순서가 중요하다는 것을 기억합니다. 먼저 필터링하는 것은 더 적은 항목을 맵하기 때문입니다. 2 또는 3 단계를 지나면 명명된 변수나 일반 루프가 종종 하나의 긴 연결보다 더 명확하게 읽힙니다.
JunoChaining and staying readable 각 단계는 통과와 할당이므로 연결은 일상적인 크기에서는 좋고 큰 데이터에 대한 핫 경로에서 한 루프나 reduce로 축약할 가치가 있습니다. 명확성은 다른 호출입니다: 연결이 각 단계가 하나의 명확한 아이디어일 때 제 위치를 획득하고, 콜백이 분기를 키우면 일반 루프가 승리합니다. 가장 짧은 것이 아니라 팀원이 가장 빨리 읽는 버전을 작성합니다.

여기서 어디로 갈 것인가

map, filter, reduce는 리스트로 하게 될 대부분의 것을 다룹니다: 변환하거나 좁히거나 축약합니다. find, some, every는 더 좁은 질문에 답합니다. 이들이 자연스러워지면 배열에 대한 루프의 대부분이 의도를 말하는 한 두 라인으로 변환됩니다.

자연스러운 다음 단계는 객체이고, 배열은 일반 숫자와 문자열보다 더 풍부한 항목을 유지하기 시작하며, 이 같은 메서드들이 계속 작동합니다. 여기서 콜백 구문이 흔들렸다면 함수를 다시 한 번 지나가면 나머지가 제자리를 찾을 것입니다.