Lodash _.maxBy() method
What you’ll learn
- How
_.maxBy(array, iteratee)projects each element to a score, picks the largest, and returns the original element. - The two iteratee shapes Lodash accepts: a function or a
_.property-style path string ('n','score.value'). - That elements whose iteratee returns
null,undefined, orNaNare silently skipped—handy and dangerous. - Why the empty-array result is
undefinedand how to default it safely with??. - Try each example in the editor (
?tryit=1,2,3) with Lodash from a CDN.
Prerequisites
Read _.max() first—_.maxBy is the same factory with an iteratee plugged in. The Math hub covers nullish defaults and the *By family idea.
- Iteratee shorthand: a string is treated as a property path, an object as a partial-match, a function as itself.
- baseExtremum: the shared loop also powers
_.max,_.min, and_.minBy—same skip rules.
Overview
Under the hood: baseExtremum(array, baseIteratee(iteratee, 2), baseGt). Each element is mapped to a score, scores compare via >, and the candidate behind the highest valid score wins. Skipping rules from _.max still apply—null, undefined, and NaN scores are dropped.
Score, then compare
Iteratee runs once per element; > compares the scores; the original element comes back.
Path shorthand
String iteratees become deep property lookups via baseIteratee—'a.b.c' just works.
Missing fields skip
If obj.sales is absent, the iteratee returns undefined—that element is ignored entirely.
Syntax
_.maxBy(array, [iteratee = _.identity]) - array: array to scan. Falsy or empty input short-circuits.
- iteratee: function, string path, or object pattern. Default is
_.identity—omit it and you get the same result as_.max(array). - Returns: the original element with the highest mapped score, or
undefined.
Lodash docs baseline (function & path)
Both calls match the documented examples: a function iteratee and the _.property shorthand.
import maxBy from "lodash/maxBy";
const objects = [{ n: 1 }, { n: 2 }];
console.log(maxBy(objects, function (o) { return o.n; })); // { n: 2 }
console.log(maxBy(objects, "n")); // { n: 2 } Nested paths & missing fields
Dotted paths drill into nested structures. Elements whose iteratee returns undefined—like rows missing the field—are quietly dropped from the contest.
import maxBy from "lodash/maxBy";
const students = [
{ id: 1, score: { value: 80 } },
{ id: 2, score: { value: 95 } },
{ id: 3, score: { value: 90 } }
];
console.log(maxBy(students, "score.value")); // { id: 2, score: { value: 95 } }
// Missing fields are skipped (note: only the first row has `sales`)
const data = [
{ id: 1, sales: 150 },
{ id: 2, revenue: 200 },
{ id: 3, profit: 180 }
];
console.log(maxBy(data, "sales")); // { id: 1, sales: 150 } Empty input, NaN scores, default iteratee
Three edges worth knowing: empty / nullish input returns undefined; NaN scores are filtered out; omitting the iteratee makes _.maxBy behave like _.max.
import maxBy from "lodash/maxBy";
console.log(maxBy([], "v")); // undefined
console.log(maxBy(null, "v")); // undefined
// Safe defaulting (use ?? not ||)
const topScore = maxBy([], "v") ?? { v: 0 };
console.log(topScore); // { v: 0 }
// NaN scores are skipped
console.log(maxBy([{ v: 1 }, { v: NaN }, { v: 3 }], "v")); // { v: 3 }
// No iteratee -> falls back to _.identity
console.log(maxBy([3, 1, 5, 2])); // 5 📋 _.maxBy vs _.max vs hand-rolled reduce
| Approach | Code | Notes |
|---|---|---|
| _.max | _.max(arr) | Single-arg only; second argument is ignored. Compares values directly. |
| _.maxBy (function) | _.maxBy(arr, o => o.price) | Most flexible; iteratee can compute derived values. |
| _.maxBy (path) | _.maxBy(arr, 'price') | Shorter; supports dotted paths like 'a.b.c'. |
| Reduce | arr.reduce((m, o) => o.price > m.price ? o : m) | Verbose, throws on empty arrays, no NaN guard. |
The reduce alternative also doesn’t handle the NaN / nullish skipping you get for free here.
Pitfalls to avoid
Don’t use ||
_.maxBy([{n:0}], 'n') || { n: -1 } “works” on empty input but also replaces real {n:0} if you ever expand the guard. Use ??.
Silent skip
If half your rows lack the property you’re ranking by, they vanish from the contest. The result reflects only rows that have the field.
No (value, index, array)
The iteratee is invoked with one argument (the value). Don’t reach for an index parameter—use arr.reduce if you need it.
Stable on ties
When two elements share the maximum score, _.maxBy keeps the first one (later ties fail the strict > check).
❓ FAQ
Summary
- Purpose: find the “biggest” element of an array using a derived score; returns the original element.
- Remember: function or string-path iteratee; missing or
NaNscores are skipped; empty/null input →undefined. - Next: Lodash _.mean(), or the official Lodash docs for _.maxBy. Pair with
_.minByfor symmetric ranking.
_.maxBy calls the iteratee with two arity hint (baseIteratee(iteratee, 2)), which is what lets the property-path shorthand like 'score.value' work the same way as obj => _.get(obj, 'score.value')—no extra parsing on your side.
6 people found this page helpful
