Lodash _.assignWith() method
What you’ll learn
- How
_.assignWith(object, ...sources, customizer)layers _.assign with a per-key decision callback. - The customizer signature
(objValue, srcValue, key, object, source)and theundefinedfallback rule. - Why this stays on own string keys—and when to prefer _.assignInWith or _.mergeWith.
- Try each example in the editor (
?tryit=1,2,3) with Lodash from a CDN.
Prerequisites
Read _.assign() first for the shared shallow/mutating semantics; this page focuses on the customizer.
- Callbacks: the customizer is a plain function called per key—treat
undefinedreturns as “defer to the default”. - Own vs inherited: know why you might want to ignore prototype data (mostly: predictability when sources are class instances).
Overview
_.assignWith is _.assign plus a per-key callback. For every key Lodash would otherwise copy, it asks the customizer for a final value first. Return undefined and Lodash uses the incoming srcValue; return anything else and you decide.
Per-key control
Sum, multiply, prefer the larger value, or keep the existing one—decide independently for each key.
undefined = fall through
A single rule keeps the customizer terse: opt out of a key by returning undefined and the default behavior applies.
Own keys only
Prototype-defined string keys are skipped—reach for _.assignInWith when you do want inherited keys.
Syntax
_.assignWith(object, [...sources], [customizer])
//
// customizer(objValue, srcValue, key, object, source) => any - object: destination object; mutated in place.
- sources: zero or more source objects; only own enumerable string keys are visited, left to right.
- customizer: last argument; return
undefinedto accept the source value, anything else to override. - Returns: the (now-mutated) destination object.
- Skipped: inherited keys (use _.assignInWith), symbol keys, non-enumerable properties, nested depth (use _.mergeWith).
Combine numeric values across sources
Sum the destination’s current value with the incoming one when both are numbers; let everything else fall through with undefined.
import assignWith from "lodash/assignWith";
const target = { a: 1, b: 2 };
const source1 = { b: 3, c: 4 };
const source2 = { d: 5 };
function sumNumbers(objValue, srcValue) {
if (typeof objValue === "number" && typeof srcValue === "number") {
return objValue + srcValue;
}
// undefined -> srcValue wins as usual
}
assignWith(target, source1, source2, sumNumbers);
// target -> { a: 1, b: 5, c: 4, d: 5 } Per-key “take the larger” rule
For a specific key ("priority") keep the maximum across destination and source. Other keys keep their default left-to-right behavior.
import assignWith from "lodash/assignWith";
const current = { priority: 2, status: "idle" };
const incoming = { priority: 5, status: "active" };
function takeMaxPriority(objValue, srcValue, key) {
if (key === "priority") {
return Math.max(objValue, srcValue);
}
}
assignWith(current, incoming, takeMaxPriority);
// current -> { priority: 5, status: "active" } Own keys only (vs assignInWith)
Inherited keys are not visited—the customizer never runs for them. Compare against _.assignInWith, where the same callback would fire for both own and inherited keys.
import assignWith from "lodash/assignWith";
import assignInWith from "lodash/assignInWith";
function Source() {
this.own = "instance";
}
Source.prototype.inherited = "prototype";
const seenW = [];
const seenInW = [];
assignWith({}, new Source(), function (o, s, k) { seenW.push(k); });
assignInWith({}, new Source(), function (o, s, k) { seenInW.push(k); });
// seenW -> ["own"]
// seenInW -> ["own", "inherited"] 📋 _.assignWith vs _.assignInWith vs _.mergeWith
| Topic | _.assignWith | _.assignInWith | _.mergeWith |
|---|---|---|---|
| Customizer signature | (objValue, srcValue, key, object, source) | Same | Same, plus stack for recursion |
| Own keys | Yes | Yes | Yes |
| Inherited keys | No | Yes | No |
| Depth | Shallow | Shallow | Recursive |
| Aliases | — | _.extendWith | — |
| Typical use | Plain objects with per-key rules | Class instances with per-key rules | Nested configs with per-key rules |
If the sources are plain object literals, _.assignWith is the smallest tool that does the job. Reach for siblings when the source shape forces you to.
Pitfalls to avoid
Forgetting the undefined fallback
A customizer that always returns a value (even null or empty string) overwrites every key. Return undefined for keys you want to leave to the default rule.
Recursing inside the customizer
It’s tempting to call _.assignWith inside itself for nested values—don’t. Use _.mergeWith, which handles recursion natively.
Destination is written in place
Pass {} as the first argument when callers share a reference and you need a fresh object.
❓ FAQ
Summary
- Purpose: shallow assignment of own enumerable string keys with a per-key customizer.
- Remember: customizer returns
undefined→ lodash usessrcValue; anything else → that value wins. - Next: Lodash _.at(), _.assignInWith(), or the official Lodash docs for _.assignWith.
_.assignWith shares its customizer signature (objValue, srcValue, key, object, source) with _.assignInWith and _.mergeWith—only the set of keys visited and the depth differ. Pick by what kind of source you have, not by what the customizer looks like.
6 people found this page helpful
