Lodash _.max() method

Beginner
⏱️ 6 min read
📚 Updated: May 2026
🎯 3 Code examples
🚀 3 Try-it labs
Lodash

What you’ll learn

  • Why _.max takes one argument, not (array, iteratee)—and how the second-arg myth silently picks the wrong element.
  • That _.max([]), _.max(null), and _.max(undefined) all return undefined (no -Infinity like Math.max()).
  • Which elements are skipped inside the array (null, undefined, NaN) and the subtle Symbol-position rule (skipped during seeding, throws afterwards).
  • How _.max uses baseGt (the > operator), so strings sort lexicographically.
  • Try each example in the editor (?tryit=1, 2, 3) with Lodash from a CDN.

Prerequisites

Familiarity with the native Math.max contract (variadic, returns -Infinity on no args) and the Math hub overview. For object-keyed maxima, head straight to _.maxBy() when published.

  • Array vs args: Math.max(a, b, c) spreads; _.max([a, b, c]) takes one array.
  • NaN propagation: Math.max(NaN, 3) is NaN; _.max([NaN, 3]) is 3.

Overview

_.max(array) walks the array once, calling baseExtremum(array, identity, baseGt). The loop guards each candidate with current != null && current === current, so nullish and NaN entries are silently skipped. The first valid value seeds the running result; later values replace it only when baseGt(current, computed) (i.e. current > computed) is true.

Single pass

O(n), no allocation beyond the result reference.

Nullish-safe

null, undefined, and NaN never participate. Symbol-first arrays skip; Symbol-mid-array throws.

No iteratee

For mapped comparisons reach for _.maxBy(arr, fn) instead.

Syntax

javascript
_.max(array)
  • array: the array to scan. Falsy or empty input short-circuits.
  • Returns: the maximum element (using >), or undefined if the array is empty/falsy or every element is skipped.
1

Lodash docs baseline

The two official examples: a numeric array and the empty case.

javascript
import max from "lodash/max";

console.log(max([4, 2, 8, 6]));   // 8
console.log(max([]));             // undefined
console.log(max(null));           // undefined
Try it Yourself
2

What gets skipped (NaN, nullish, Symbols)

Where native Math.max(...arr) returns NaN if any element is non-numeric, _.max quietly skips null, undefined, and NaN. Symbols are different: skipped while looking for the first seed, but a Symbol after a non-Symbol value lands in baseGt's > and throws.

javascript
import max from "lodash/max";

console.log(max([1, NaN, 3, 2]));            // 3
console.log(max([NaN, NaN]));                // undefined  (every value skipped)
console.log(max([1, null, undefined, 3]));    // 3
console.log(max([Symbol("a"), 1, 2]));        // 2   (Symbol skipped during seeding)

// Symbol AFTER a seed -> throws
try {
  console.log(max([1, Symbol("x"), 2]));
} catch (err) {
  console.log("Threw:", err.message);          // "Cannot convert a Symbol value to a number"
}

// Compare with native
console.log(Math.max(1, NaN, 3, 2));          // NaN
Try it Yourself
3

Strings, and the “_.max(arr, iteratee)” trap

Strings compare lexicographically via >. For objects, _.max compares the objects themselves—which is never useful—and silently ignores any second argument. Reach for _.maxBy.

javascript
import max from "lodash/max";
import maxBy from "lodash/maxBy";

console.log(max(["banana", "apple", "cherry"])); // "cherry"

const items = [
  { id: 1, value: 15 },
  { id: 2, value: 25 },
  { id: 3, value: 10 }
];

// Trap: _.max ignores the second argument; returns the first item
console.log(max(items, o => o.value));   // { id: 1, value: 15 }

// Correct API
console.log(maxBy(items, o => o.value)); // { id: 2, value: 25 }
console.log(maxBy(items, "value"));       // { id: 2, value: 25 }
Try it Yourself

📋 _.max vs Math.max

Input_.max(arr)Math.max(...arr)
[4, 2, 8, 6]88
[]undefined-Infinity
[1, NaN, 3]3NaN
[1, null, 3]33 (null coerces to 0)
['banana', 'cherry']'cherry'NaN
arr, iterateeiteratee ignoredn/a

The empty-array row is the biggest behavioral difference: _.max([]) is friendlier than -Infinity for “no data” states.

Pitfalls to avoid

Myth

There is no iteratee parameter

_.max(items, o => o.value) silently returns the first item because the second argument is ignored. The correct API is _.maxBy(items, fn).

Empty

Empty → undefined

Default with ?? when you display it: _.max(scores) ?? 0. || would replace a legitimate 0 with the fallback.

Skipping

Silent NaN filter

Sometimes you want to know there were bad samples. _.max won’t tell you; pre-validate with arr.some(Number.isNaN) if it matters.

Strings

Lexicographic vs numeric

String comparison is by code point: _.max(['9', '10']) is '9'. Coerce first if you have digit strings.

❓ FAQ

No. In Lodash 4.x the signature is _.max(array)—only one argument. Passing a second argument is silently ignored, which is a famous footgun: _.max([{v:1},{v:5}], o => o.v) returns {v:1}, not {v:5}. Use _.maxBy for that.
undefined. Same for null, undefined, or any falsy input. Unlike Math.max(), there is no -Infinity sentinel.
Skipped. baseExtremum checks current != null && current === current, so non-comparable entries don't participate. _.max([1, NaN, null, 3]) is 3. If every element is skipped, you get undefined.
Symbols are only skipped while looking for the first seed value. Once a non-Symbol seed exists, a later Symbol falls through to baseGt's > operator and throws 'Cannot convert a Symbol value to a number'. Filter symbols out first if your data might contain them.
Yes. baseGt uses the > operator, so strings compare lexicographically: _.max(['banana','apple','cherry']) is 'cherry'. Mixed numeric/string arrays follow JavaScript's coercion rules—usually unsurprising for digit strings but easy to misread otherwise.
Use import max from "lodash/max"; or const max = require('lodash/max'). Tree-shake-friendly and pulls only ~30 lines of helpers.

Summary

  • Purpose: single-pass max over an array, ignoring nullish and NaN entries (Symbols only skip during seeding; mid-array Symbols throw).
  • Remember: one argument only; falsy/empty input returns undefined; strings compare lexicographically.
  • Next: Lodash _.maxBy() for object arrays, or the official Lodash docs for _.max.
Did you know?

_.max is the one-argument shortcut baseExtremum(array, identity, baseGt). The internal guard silently skips null, undefined, and NaN_.max([1, NaN, 3]) returns 3, and _.max([NaN, NaN]) returns undefined because every candidate was skipped. Symbols are only skipped while looking for the first seed; a Symbol that appears after a valid value falls through to baseGt's > and throws.

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

6 people found this page helpful