Pick the check by what you're asking:
| Question | Check |
|---|---|
Is it a string, number, boolean, bigint, symbol, or undefined? |
typeof value === '…' |
| Is it a function? | typeof value === 'function' |
Is it null? |
value === null (typeof null is "object") |
| Is it an array? | Array.isArray(value) |
| Is it an error? | Error.isError(value) where available |
| Is it an instance of my class? | value instanceof MyClass |
Is it NaN? |
Number.isNaN(value) (not the global isNaN, which coerces) |
| Which built-in kind is it? | Object.prototype.toString.call(value) |
Why the simple tools fail:
typeofknows eight results only. Arrays, dates, regexes andnullare all"object".instanceofchecks whetherConstructor.prototypeis on the value's prototype chain (or callsConstructor[Symbol.hasInstance]). It's false for primitives ('s' instanceof Stringisfalse), true for any object that merely inherits from the prototype, and breaks across realms (iframes,vmcontexts), because each realm has its ownArrayandError.Array.isArrayandError.isErrorare branded checks: they look at internal slots (an Array exotic object;[[ErrorData]]), not the prototype chain. They work across realms and aren't fooled by{ __proto__: Array.prototype }.Array.isArrayalso sees through aProxyto its target.Error.isErroris newer and MDN lists it as not Baseline, so feature-detect it or use a polyfill.Object.prototype.toString.call(v)returns[object Tag]:NullandUndefinedfor those values; otherwise the value of the object'sSymbol.toStringTagproperty if that's a string, else a built-in tag (Array,Arguments,Function,Error,Boolean,Number,String,Date,RegExp) orObject. The spec says this isn't a reliable test for other objects, since programs can setSymbol.toStringTagthemselves.