Difference Between Lodash _.isNaN and Number.isNaN
While both _.isNaN from Lodash and the native ES6
Number.isNaN solve the type-coercion issues of the legacy
global isNaN function, their primary distinction lies in
how they handle primitive values versus Number object
instances. Both methods ensure that non-numeric types are not coerced
into NaN, but _.isNaN is designed to recognize
NaN even when it is wrapped in an instantiated
Number object, whereas Number.isNaN strictly
evaluates primitive numeric values.
The Problem with Global
isNaN
To understand both implementations, consider the legacy global
isNaN function. The global function performs implicit type
coercion, converting the passed argument to a number before
evaluation:
isNaN("hello"); // true, because Number("hello") is NaN
isNaN(undefined); // true, because Number(undefined) is NaNThis behavior leads to false positives for values that are not the
actual numeric NaN value.
ECMAScript 2015:
Number.isNaN
ES6 introduced Number.isNaN to address this issue with
strict type checking. According to the ECMAScript specification,
Number.isNaN(value) first checks if the type of the
argument is strictly a primitive number. If it is not, it
immediately returns false. Only if the value is both a
primitive number and evaluates to NaN will it return
true.
Number.isNaN(NaN); // true
Number.isNaN("hello"); // false (no coercion)
Number.isNaN(undefined); // false (no coercion)
Number.isNaN(new Number(NaN)); // falseBecause new Number(NaN) returns an object rather than a
primitive, Number.isNaN rejects it.
Lodash: _.isNaN
Lodash provides _.isNaN to identify NaN
values safely across varied JavaScript runtime quirks and legacy
patterns. Unlike Number.isNaN, Lodash checks whether the
value is either a primitive number or a boxed Number object
before validating whether the value represents NaN.
Internally, Lodash verifies that the value has an internal
[[Class]] or Symbol.toStringTag of
[object Number], combined with a check where the value does
not equal itself:
_.isNaN(NaN); // true
_.isNaN("hello"); // false
_.isNaN(undefined); // false
_.isNaN(new Number(NaN)); // trueKey Differences Summary
- Primitive Values: Both functions return
truefor primitiveNaNandfalsefor any non-numeric primitive, such as strings, booleans,null, andundefined. - Object-Wrapped Numbers:
Number.isNaN(new Number(NaN))evaluates tofalsebecause it strictly checks for the primitive type. In contrast,_.isNaN(new Number(NaN))evaluates totruebecause it unpacks or checks the object-wrapped numeric value. - Environment and Performance:
Number.isNaNis a built-in native method executing at engine-level speed without third-party dependencies._.isNaNrequires importing the Lodash library and runs JavaScript-level object type inspections.
For modern codebases where new Number() object wrappers
are rarely, if ever, used, Number.isNaN is the standard
native solution. _.isNaN remains useful in legacy projects
or environments where boxed number instances must be accommodated.