indexOf, lastIndexOf
배열 안에서 뭔가 찾으려 할 때는 몇 가지 방법이 있습니다.
indexOf 부터 알아봅시다.
indexOf는 찾고자 하는 것과 정확히 일치(===)하는 첫 번째 요소의 인덱스를 반환합니다.
indexOf의 짝인 lastIndexOf는 배열의 끝에서부터 검색합니다.
배열의 일부분만 검색하려면 시작 인덱스를 지정할 수 있습니다.
indexOf와 lastIndexOf는 일치하는 것을 찾지 못하면 -1을 반환합니다.
const o = {name: "Jerry"};
const arr = [1, 5, "a", o, true, 5, [1, 2], "9"];
arr.indexOf(5); // 1
arr.lastIndexOf(5); // 5
arr.indexOf("a"); // 2
arr.lastIndexOf("a"); // 2
arr.indexOf({name: "Jerry"}); // -1
arr.indexOf(o); // 3
arr.indexOf([1, 2]); // -1
arr.indexOf("9"); // 7
arr.indexOf(9); // -1
arr.indexOf("a", 5); // -1
arr.indexOf(5, 5); // 5
arr.lastIndexOf(5, 4); // 1
arr.lastIndexOf(true, 3); // -1
findIndex
findIndex는 일치하는 것을 찾지 못했을 때 -1을 반환한다는 점에서는 indexOf와 비슷하지만, 보조 함수를 써서 검색 조건을 지정할 수 있으므로 indexOf 보다 더 다양한 상황에서 활용할 수 있습니다.
하지만 findIndex는 검색을 시작할 인덱스를 지정할 수 없고, 뒤에서부터 찾는 findLastIndex 같은 짝도 없습니다.
const arr = [{ id: 5, name: "Judith" }, { id: 7, name: "Francis" }];
arr.findIndex(o => o.id === 5); // 0
arr.findIndex(o => o.name === "Francis"); // 1
arr.findIndex(o => o === 3); // -1
arr.findIndex(o => o.id === 17); // -1
find
indexOf와 findIndex는 조건에 맞는 요소의 인덱스를 찾을 때 알맞지만,
조건에 맞는 요소의 인덱스가 아니라 요소 자체를 원할 때는 find를 사용합니다.
find는 findIndex와 마찬가지로 검색 조건을 함수로 전달할 수 있습니다.
조건에 맞는 요소가 없을 때는 undefined를 반환합니다.
const arr = [{ id: 5, name: "Judith" }, { id: 7, name: "Francis" }];
arr.find(o => o.id === 5); // 객체 {id: 5, name: "Judith"}
arr.find(o => o.id === 2); // undefined
find와 findIndex에 전달하는 함수는 배열의 각 요소를 첫 번째 매개변수 로 받고, 현재 요소의 인덱스와 배열 자체도 매개변수 로 받습니다. 이런 점을 다양하게 응용할 수 있습니다.
예를 들어, 특정 인덱스보다 뒤에 있는 제곱수를 찾아야 한다고 합시다.
const arr = [1, 17, 16, 5, 4, 16, 10, 3, 49];
arr.find((x, i) => i > 2 && Number.isInteger(Math.sqrt(x))); // 4
find와 findIndex에 전달하는 함수의 this도 수정할 수 있습니다.
이를 이용해서 함수가 객체의 메서드인 것처럼 호출할 수 있습니다.
ID를 조건으로 Person 객체를 검색하는 예제를 보십시오.
두 방법의 결과는 같습니다.
class Person {
constructor(name) {
this.name = name;
this.id = Person.nextId++;
}
}
Person.nextId = 0;
const jamie = new Person("Jamie"),
juliet = new Person("Juliet"),
peter = new Person("Peter"),
jay = new Person("Jay");
const arr = [jamie, juliet, peter, jay];
// 옵션 1 : ID를 직접 비교하는 방법
arr.find(p => p.id === juliet.id); // juliet 객체
// 옵션 2 : "this" 매개변수를 이용하는 방법
arr.find(function (p) {
return p.id === this.id
}, juliet); // juliet 객체
이렇게 간단한 예제에서는 find와 findIndex에서 this 값을 바꾸는 의미가 별로 없지만, 나중에 이 방법이 더 유용하게 쓰이는 경우를 보게 될 겁니다.
간혹 조건을 만족하는 요소의 인덱스도, 요소 자체도 필요 없고, 조건을 만족하는 요소가 있는지 없는지만 알면 충분할 때가 있습니다.
물론 앞에서 설명한 함수를 사용하고 -1 이나 null이 반환되는지 확인해도 되지만, 자바스크립트에는 이럴 때 쓰라고 만든 some과 every 메서드가 있습니다.
some
some은 조건에 맞는 요소를 찾으면 즉시 검색을 멈추고 true를 반환하며, 조건에 맞는 요소를 찾지 못하면 false를 반환합니다.
예제를 보십시오.
const arr = [5, 7, 12, 15, 17];
arr.some(x => x%2 === 0); // true; 12는 짝수입니다.
arr.some(x => Number.isInteger(Math.sqrt(x))); // false; 제곱수가 없습니다.
every
every는 배열의 모든 요소가 조건에 맞아야 true를 반환하며 그렇지 않다면 false를 반환합니다.
every는 조건에 맞지 않는 요소를 찾아야만 검색을 멈추고 false를 반환합니다.
조건에 맞지 않는 요소를 찾지 못하면 배열 전체를 검색합니다.
const arr = [4, 6, 16, 36];
arr.every(x => x%2 === 0); // true; 홀수가 없습니다.
arr.every(x => Number.isInteger(Math.sqrt(x))); // false; 6은 제곱수가 아닙니다.
이 장에서 소개하는 메서드 중 콜백 함수를 받는 모든 메서드가 그렇듯, some 과 every도 콜백 함수를 호출할 때 this로 사용할 값을 두 번째 매개변수로 받을 수 있습니다.