Stop using .reverse().find(): meet findLast()
If you’ve ever needed to search an array from the end, you’ve probably used .slice().reverse().find(...), or looped backward manually. It works, but it’s clunky.
We now have a better way: Array.prototype.findLast() and Array.prototype.findLastIndex(). They search from the end without reversing anything.
The problem with reversing arrays
Working with lists in front-end apps (e.g., chat messages, activity logs, form history, etc.) often involves finding the last matching item. Prior to ES2023, you’d typically do something like:
const lastError = [...logs].reverse().find(log => log.type === 'error');
- Reverses a cloned array, which is inefficient
- Risky if you forget to clone (
.slice()) - Less readable and more error-prone
Now, you can write:
const lastError = logs.findLast(log => log.type === 'error');
- No copying or reversing
- Cleaner and clearer
- Safer and more performant, especially with large datasets
findLast(predicate)
This method works just like .find(), but starts at the end of the array and moves backward. It takes a predicate, a function that returns true or false, for each item.
const messages = [
{ id: 1, text: 'Hello', read: true },
{ id: 2, text: 'Hi', read: false },
{ id: 3, text: 'Hey', read: true },
];
const lastUnread = messages.findLast(msg => !msg.read);
console.log(lastUnread);
// { id: 2, text: 'Hi', read: false }
Like .find(), the predicate receives three arguments: (element, index, array):
array.findLast((element, index, array) => {
// Use these if needed
});
const arr = [1, , 3, , 5];
console.log(arr.findLast(x => true)); // 5
const arr = [1, undefined, 3, , 5];
console.log(arr.findLast(x => x === undefined)); // This finds the actual `undefined`, not a hole
// Index 0: 1
// Index 1: undefined
// Index 2: 3
// Index 3: <hole>
// Index 4: 5
findLastIndex(predicate)
If you need the index instead of the item, use findLastIndex():
const lastUnreadIndex = messages.findLastIndex(msg => !msg.read);
console.log(lastUnreadIndex); // 1
console.log(messages[lastUnreadIndex]); // { id: 2, text: 'Hi', read: false }
Solving real problems
A few places where these come in handy:
Find the last login event
const events = [
{ type: 'login', user: 'A' },
{ type: 'logout', user: 'A' },
{ type: 'login', user: 'B' },
];
const lastLogin = events.findLast(e => e.type === 'login');
Find the last unread message in a chat app
const messages = [
{ id: 1, read: true },
{ id: 2, read: true },
{ id: 3, read: false },
];
const lastUnread = messages.findLast(msg => !msg.read);
Find the last failed validation in a <form>
const fields = [
{ name: 'email', valid: true },
{ name: 'password', valid: false },
{ name: 'username', valid: false },
];
const lastInvalid = fields.findLast(f => !f.valid);
Find the last manual save in a document editor
const versions = [
{ id: 1, type: 'auto-save' },
{ id: 2, type: 'manual-save' },
{ id: 3, type: 'auto-save' },
];
const lastManualSave = versions.findLast(v => v.type === 'manual-save');
A React example
Let’s say you’re managing user actions in a React component:
const actions = [
{ type: 'click', target: 'button' },
{ type: 'scroll' },
{ type: 'click', target: 'link' },
];
// Find the last click on a button
const lastButtonClick = actions.findLast(
action => action.type === 'click' && action.target === 'button'
);
Instead of juggling reversed arrays or writing awkward loops, the code just says what you’re looking for.
Common pitfalls & best practices
-
reverse()mutates the original array:const arr = [1, 2, 3]; arr.reverse(); console.log(arr); // [3, 2, 1], the original is changed!That’s why
findLast()andfindLastIndex()are safer alternatives. -
Empty arrays return
undefined, just like.find():[].findLast(() => true); // undefined - These methods return only the first match from the end, not all matches.
- They skip holes in sparse arrays, but not values that are explicitly
undefined. - They only work on real arrays, not array-like objects like
arguments,NodeList, or strings.
-
You can convert those real arrays with
Array.from()or spread syntax:const lastItem = [...nodeList].findLast(...); -
They work on subclassed arrays too:
class MyArray extends Array {} const arr = new MyArray(1, 2, 3, 4); const lastEven = arr.findLast(x => x % 2 === 0); // 4
Browser support
- ✅ Chrome 97+, Safari 16.4+, Edge 97+, Firefox 104+
- ✅ Node.js 18.12+
If you’re supporting older environments, use a polyfill or transpile with core-js.
In short
findLast() and findLastIndex() are small additions, but they replace the slice().reverse() pattern with something shorter, safer, and easier to read.
Try them out, see what you think!