JavaScript find와 filter 차이
find()와 filter()는 배열에서 조건을 만족하는 요소를 찾는다.
콜백이 truthy를 반환한 요소를 선택한다는 점은 같지만 필요한 결과의 개수가 다르다.
요소 하나가 필요하면 find(), 조건을 통과한 목록이 필요하면 filter()를 선택한다.
find와 filter의 반환값
find()는 조건을 만족한 첫 번째 요소 자체를 반환한다.filter()는 조건을 만족한 모든 요소를 담은 새 배열을 반환한다.
const users = [
{ id: 1, role: 'admin' },
{ id: 2, role: 'member' },
{ id: 3, role: 'admin' },
]
const firstAdmin = users.find((user) => user.role === 'admin')
const allAdmins = users.filter((user) => user.role === 'admin')
console.log(firstAdmin)
// { id: 1, role: 'admin' }
console.log(allAdmins)
// [{ id: 1, role: 'admin' }, { id: 3, role: 'admin' }]결과 하나만 필요한데 filter(...)[0]을 쓰면 필요하지 않은 결과 배열까지 만든다.
의도와 반환 형태를 같이 드러내려면 find()를 바로 사용하는 편이 낫다.
순회 종료 시점
find()는 콜백이 처음 truthy를 반환하면 해당 요소를 반환하고 순회를 끝낸다.filter()는 결과 배열을 완성해야 하므로 할당된 요소를 끝까지 검사한다.
const numbers = [4, 12, 18, 3]
let findCalls = 0
let filterCalls = 0
numbers.find((number) => {
findCalls += 1
return number > 10
})
numbers.filter((number) => {
filterCalls += 1
return number > 10
})
console.log(findCalls) // 2
console.log(filterCalls) // 4이 차이는 첫 일치 항목이 앞쪽에 있을 때 분명해진다.
다만 메서드를 성능 기법으로만 고르지 말고 필요한 결과 형태를 먼저 기준으로 삼는다.
반환 객체와 원본 참조
find()가 반환하는 객체는 원본 배열에 들어 있던 객체다.filter()는 새 배열을 만들지만 배열 안의 객체까지 복제하지는 않는다.
const users = [{ id: 1, active: true }]
const found = users.find((user) => user.id === 1)
const filtered = users.filter((user) => user.id === 1)
console.log(found === users[0]) // true
console.log(filtered[0] === users[0]) // true
filtered[0].active = false
console.log(users[0].active) // false두 메서드 자체는 원본 배열에 요소를 추가하거나 제거하지 않는다.
그러나 콜백이나 반환된 객체를 통해 객체 속성을 바꾸면 원본에도 반영된다.
일치 항목이 없는 경우와 희소 배열
일치하는 요소가 없으면 find()는 undefined, filter()는 빈 배열을 반환한다.
따라서 find() 결과는 사용하기 전에 없을 수 있음을 처리해야 한다.
희소 배열에서는 콜백 호출 규칙도 다르다.find()는 빈 슬롯을 undefined처럼 방문하지만 filter()는 빈 슬롯을 건너뛴다.
console.log([1, 2].find((number) => number > 10)) // undefined
console.log([1, 2].filter((number) => number > 10)) // []
const values = [1, , undefined]
console.log(values.find((value) => value === undefined)) // undefined
console.log(values.filter((value) => value === undefined)) // [undefined]
const assignedUndefinedIndex = values.findIndex(
(value, index, array) => index in array && value === undefined,
)
console.log(assignedUndefinedIndex) // 2배열 요소 자체가 undefined일 수 있으면 find()의 반환값만으로는 찾았는지 구분할 수 없다.
이 경우에는 findIndex()로 -1인지 확인하고, 빈 슬롯과 직접 넣은 undefined까지 구분해야 한다면 index in array를 함께 검사한다.
배열 검색 메서드 선택 기준
조건을 만족하는 첫 요소가 필요하면 find()를 사용한다.
조건을 만족하는 모든 요소가 필요하면 filter()를 사용한다.
요소가 있는지만 확인하려면 some(), 위치가 필요하면 findIndex()가 더 직접적이다.
콜백 조건이 아닌 특정 값의 존재 여부는 includes()로 표현할 수 있다.
배열의 모든 요소를 변환하거나 작업을 실행하는 기준은 JavaScript map과 forEach 차이에서 이어서 볼 수 있다.
최종적으로 필요한 결과가 요소 하나인지, 배열인지, boolean인지를 먼저 정하면 메서드 선택이 단순해진다.
참고 자료


















