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);
Like .find()
, the predicate receives three arguments: (element, index, array)
:
array.findLast((element, index, array) => { });
⚠️ Note: findLast()
skips empty slots (a.k.a. “holes”) in sparse arrays, just like .find()
:
const arr = [1, , 3, , 5];
console.log(arr.findLast(x => true));
⚠️ Note: A “hole” is different from an undefined
value. For example:
const arr = [1, undefined, 3, , 5];
console.log(arr.findLast(x => x === undefined));
findLastIndex(predicate)
If you need the index instead of the item, use findLastIndex()
:
const lastUnreadIndex = messages.findLastIndex(msg => !msg.read); console.log(lastUnreadIndex); console.log(messages[lastUnreadIndex]);
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.
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' },
]; 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);
That’s why
findLast()
andfindLastIndex()
are safer alternatives. -
Empty arrays return
undefined
, just like.find()
:[].findLast(() => true);
-
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.
Looking for cleaner ways to index arrays? Learn how the .at()
method in JavaScript simplifies array access. No more length - 1
gymnastics!
-
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);
Want to know why mutating array methods like reverse()
can lead to bugs? Learn about safer, non-mutating alternatives.
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!