Stop using .reverse().find(): meet findLast()

2 min read

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() and findLastIndex() 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!