Stop using .reverse().find(): meet findLast()
If you’ve ever needed to search an array from the end, you’ve probably reached for a combination of .slice().reverse().find(...)
, or looped backward manually. It works, but it’s not an elegant solution.
We now have a better way: Array.prototype.findLast()
and Array.prototype.findLastIndex()
. These features let you search arrays from the end without reversing them, which gives you cleaner and more intuitive code.
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
There are a number of practical scenarios and use cases that come up frequently in UI work where findLast()
and findLastIndex()
stand out.
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');
Perfect for React UIs
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, your logic stays focused on the intent.
Common pitfalls & best practices
-
reverse()
mutates the original array:const arr = [1, 2, 3]; arr.reverse(); console.log(arr); // [3, 2, 1] — 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.
Let’s recap
findLast()
and findLastIndex()
are small additions, but they solve a long-standing gap in the language. They eliminate the need for patterns like slice().reverse()
, lead to more readable and intent-driven code, and offer a safer, more performant approach for working with large datasets.
Try them out, see what you think!