Bạn cần lấy một người dùng theo ID nhưng code đang gọi filter rồi đọc phần tử đầu. Đoạn đó có thể chạy, song kiểu kết quả và cách xử lý dữ liệu trùng cần được xem lại trước khi đổi tên method để “tối ưu”.
Bài so sánh cùng các tiêu chí: yêu cầu kết quả, trường hợp không có kết quả, lượng công việc quan sát được và độ dễ review. Các snippet đã chạy trên Node.js 24.18.1, đối chiếu MDN ngày 01/11/2026. Không có benchmark mili giây hoặc kết luận tốc độ trên dữ liệu sản phẩm.
1. Cùng predicate, hợp đồng kết quả khác
find trả phần tử đầu tiên thỏa điều kiện hoặc undefined. filter trả một array gồm các phần tử thỏa điều kiện, có thể là array rỗng. Cả hai có sẵn trong JavaScript hiện đại, không cần dependency hoặc dịch vụ ngoài.
import assert from 'node:assert/strict';
const users = [
{id: 1, role: 'reader'},
{id: 2, role: 'editor'},
{id: 3, role: 'editor'},
];
const firstEditor = users.find(user => user.role === 'editor');
const allEditors = users.filter(user => user.role === 'editor');
assert.equal(firstEditor.id, 2);
assert.deepEqual(allEditors.map(user => user.id), [2, 3]);
assert.equal(users.find(user => user.id === 99), undefined);
assert.deepEqual(users.filter(user => user.id === 99), []);
console.log(firstEditor.id, allEditors.length);
Nếu UI cần hiển thị tất cả editor, đổi filter thành find làm mất dữ liệu hợp lệ. Nếu chỉ cần một phần tử được quy định rõ, find diễn đạt mục đích trực tiếp hơn việc tạo array rồi lấy index 0.
2. Quan sát số lần gọi, không biến thành benchmark
Trên array đặc bình thường và predicate không sửa dữ liệu, find dừng khi đã có kết quả. filter cần xét các phần tử để thu các kết quả còn lại. Có thể nhìn thấy khác biệt bằng counter thay vì đo một khoảng thời gian quá nhỏ rồi tuyên bố thắng tuyệt đối.
import assert from 'node:assert/strict';
const values = [10, 20, 30, 40];
let findCalls = 0;
let filterCalls = 0;
const found = values.find(value => {
findCalls += 1;
return value >= 20;
});
const selected = values.filter(value => {
filterCalls += 1;
return value >= 20;
});
assert.equal(found, 20);
assert.deepEqual(selected, [20, 30, 40]);
assert.equal(findCalls, 2);
assert.equal(filterCalls, 4);
console.log(findCalls, filterCalls);
Fixture đã cho 2 và 4 lần gọi. Đó là bằng chứng về đường đi trên bốn phần tử này, không phải tỷ lệ tăng tốc gấp đôi. Nếu kết quả ở cuối hoặc không tồn tại, find cũng có thể cần đi qua cả array.
Về chi phí vận hành, hai lựa chọn đều chạy local trong runtime. Chi phí thực tế còn phụ thuộc predicate, kích thước dữ liệu và công việc bao quanh. Nếu việc tìm kiếm là điểm nghẽn lặp lại, cần đo trên use case trước khi thay cấu trúc dữ liệu.
3. Đừng dùng truthiness để suy ra có kết quả
Một phần tử hợp lệ có thể là 0 hoặc false. Khi dùng find trên những kiểu đó, kiểm tra if (found) có thể gộp nhầm “tìm thấy giá trị falsy” vào “không tìm thấy”.
import assert from 'node:assert/strict';
const value = [0, 1, 2].find(item => item === 0);
assert.equal(value, 0);
assert.equal(Boolean(value), false);
assert.notEqual(value, undefined);
const index = [undefined, 'ok'].findIndex(item => item === undefined);
assert.equal(index, 0);
console.log(value, index);
Nếu array có thể chứa chính undefined và bạn cần phân biệt “tìm thấy undefined” với “không tìm thấy”, findIndex là một lựa chọn đáng xem xét. Kiểm tra index khác -1; index 0 vẫn là vị trí hợp lệ.
4. Dữ liệu trùng là quyết định nghiệp vụ
find lấy kết quả đầu không chứng minh ID duy nhất. Nếu dữ liệu trùng là lỗi, dùng cơ chế kiểm tra tính duy nhất ở nơi dữ liệu được tạo hoặc nạp vào, rồi báo lỗi rõ ràng. Không đổi từ filter sang find chỉ để giấu các bản ghi trùng ở cuối.
filter tạo array mới nhưng không tự clone sâu các object bên trong. Ví dụ tập trung việc chọn phần tử; đừng suy rằng sửa object trong kết quả luôn tách biệt với nguồn. Với array thưa hoặc predicate sửa array trong khi duyệt, đọc thêm hợp đồng method trước khi áp dụng suy luận của fixture đặc này.
Chọn và kiểm tra
Chọn find cho phần tử đầu tiên, filter cho tập kết quả và findIndex khi vị trí là thông tin cần lấy. Thử array rỗng, không có kết quả, nhiều kết quả và giá trị hợp lệ bằng 0. Tên biến như firstEditor hoặc allEditors cũng giúp reviewer phát hiện lựa chọn sai trước khi chạy code.

