Một trang lịch sử hiển thị danh sách theo thứ tự cũ đến mới. Bạn muốn đọc bản ghi hoàn thành cuối cùng mà không thay đổi thứ tự hiển thị. Dùng reverse rồi find có vẻ tự nhiên, nhưng reverse trên chính mảng đầu vào sẽ đổi thứ tự của dữ liệu dùng chung.
Bài này đối chiếu ba lựa chọn trên cùng một fixture: findLast, vòng lặp ngược và tạo bản sao rồi đảo. Tiêu chí là hành vi khi không khớp, thay đổi đầu vào, lượng công việc thể hiện trong code và khả năng dùng trên runtime đích. Không đo tốc độ thực tế.
Bản ghi cuối là cuối theo index
Giả sử mảng đã được sắp xếp theo thời điểm mà sản phẩm cần. findLast tìm từ index lớn xuống nhỏ và dừng khi điều kiện khớp. Nó không đọc timestamp để quyết định bản ghi mới nhất. Nếu server gửi dữ liệu lộn thứ tự, tìm cuối và tìm lớn nhất theo thời điểm là hai bài toán khác nhau.
const assert = require('node:assert/strict');
const history = [
{id: 'a', state: 'done'},
{id: 'b', state: 'done'},
{id: 'c', state: 'pending'},
];
const done = row => row.state === 'done';
function findBackward(rows, predicate) {
for (let index = rows.length - 1; index >= 0; index--) {
if (predicate(rows[index])) return rows[index];
}
return undefined;
}
const last = history.findLast(done);
assert.equal(last.id, 'b');
assert.equal(findBackward(history, done), last);
assert.equal([...history].reverse().find(done), last);
assert.deepEqual(history.map(row => row.id), ['a', 'b', 'c']);
assert.equal(history.findLast(row => row.state === 'failed'), undefined);
Fixture dùng mảng đặc có các object cùng hình dạng. Cả ba cách trả cùng object b. Kiểm tra thứ tự sau khi chạy giúp phát hiện lỗi nếu ai đó bỏ phần tạo bản sao và gọi reverse trực tiếp trên history.
So sánh để chọn cách viết
findLast thể hiện ngay hướng tìm và không yêu cầu tạo mảng đảo riêng. Ưu tiên nó khi nhóm đã xác nhận môi trường đích hỗ trợ API. Ví dụ được kiểm tra trên Node 24.18.1; điều đó không tự xác nhận một browser cũ hay JavaScript engine trong app mobile.
Vòng lặp ngược thể hiện rõ index và có thể dùng khi cần ghi lại vị trí hoặc thêm điều kiện dừng riêng. Đổi lại, người review cần kiểm tra chỉ số bắt đầu, điều kiện kết thúc và giá trị trả về khi không có kết quả. Đoạn mẫu chỉ là fallback cho dữ liệu trong fixture, không phải polyfill đầy đủ cho các receiver đặc biệt.
Sao chép rồi đảo có thể dễ hiểu khi bạn đã cần một bản trình bày đảo thứ tự cho công việc khác. Chỉ để tìm một phần tử, nó tạo thêm mảng và đảo toàn bộ trước khi tìm. Đây là nhận xét về thao tác trong code, không phải kết quả benchmark.
Lỗi thường gặp
Kết quả là object gốc, không phải bản sao sâu. Nếu tiếp tục sửa last.state, bạn đang sửa object mà history tham chiếu. Tách việc tìm và việc cập nhật khi dữ liệu đi qua một store yêu cầu cập nhật bất biến.
Nếu không tìm thấy, xử lý undefined trước khi đọc id. Thêm ca mảng rỗng và ca có nhiều bản ghi khớp. Khi dữ liệu có phần tử thiếu hoặc null, điều kiện cần kiểm tra hình dạng trước khi đọc state; ví dụ không xử lý dữ liệu đó.
Kết luận
Chọn findLast khi cần khớp cuối theo thứ tự hiện có và runtime hỗ trợ. Giữ một fixture xác nhận phần tử được chọn và thứ tự mảng sau thao tác; cả hai đều thuộc hợp đồng của màn hình.


