DEV Community

Alex M
Alex M

Posted on • Edited on

How to Check if a Value is an Object in JavaScript

There are several strategies to check if a value is an object. The primary reason is that in JavaScript, any non-primitive type (primitives: string, number, bigint, boolean, undefined, symbol, and null) is treated as an object, but depending on the checking method, there are considerations to take into account.

Using typeof operator

JavaScript provides the typeof operator to check the value data type.

The typeof operator returns a string indicating the type of the operand's value.

typeof variable === 'object' returns true for:

  • objects
  • null 😶
  • arrays
  • regular expressions
  • new Date()
  • new Map()
  • new Set()

So these validation could be required.

code

const isObject = (value) => {
  return typeof value === 'object'
  && value !== null
  && !Array.isArray(value)
  && !(value instanceof RegExp)
  && !(value instanceof Date)
  && !(value instanceof Set)
  && !(value instanceof Map)
}
Enter fullscreen mode Exit fullscreen mode

Using instanceof operator

Just like typeof, multiple validations may be necessary.

variable instanceof Object returns true for:

  • functions
  • arrays
  • regular expressions
  • new Date()
  • new Map()
  • new Set()

NOTE: instanceof returns false for objects initialised as Object.create(null) even after set additional properties.
(Object.create(null) is used explicitly when an object without prototype chain, any properties or methods from Object.prototype is needed)

code

const user = Object.create(null)
user.id = 'A0012'
const client = Object.create(user)
const isObject = user instanceof Object
const isClientObj = client instanceof Object
Enter fullscreen mode Exit fullscreen mode

test

test('user should be an object', () => {
 expect(isObject).toBeTruthy()
})

test('client should be an object', () => {
 expect(isClientObj).toBeTruthy()
})
Enter fullscreen mode Exit fullscreen mode

FAIL user should be an object
FAIL client should be an object

💪 ✨ Object.prototype.toString.call()✨

This method returns the stringified type identifier, like [object Object], [object Array]...

NOTE: toString.call() instead of toString() is used to prevent unexpected behaviour due this.

The advantage of this strategy is that it distinguishes all types with specificity, such as Array, RegExp, etc. and it doesn't throw Uncaught TypeError.

code

const user = {}
const isObj = Object.prototype.toString.call(user) === '[object Object]'
Enter fullscreen mode Exit fullscreen mode

test

test('user should be an object', () => {
 expect(isObject).toBeTruthy()
})
Enter fullscreen mode Exit fullscreen mode

✅ PASS user should be an object

The ability to return the specific type of the value allows for easy validation of other types, with the only observation that values created with a constructor and new keyword may behave differently than expected.

Ex: Object.prototype.toString.call(new Number(3)), Object.prototype.toString.call(Number(3)), and Object.prototype.toString.call(3) all return '[object Number]'.

✨ Using constructor property

The constructor data property returns a reference to the constructor function that created the instance object

Similar to Object.prototype.toString.call() gives the chance to know the specific type

With three important observations:

  • variable.constructor === Object returns false for Object.create(null)
  • It throws Uncaught TypeError for null and undefined
  • Since the constructor property can potentially be overwritten, like { constructor: 1 }, it may not be reliable.

Some extra validation should be necessary (This solution does not take into account the override of constructor property):

code

const isObject = (value) => {
  return value != null // equality operator checks `undefined` and `null`
  && 
  (value.constructor === Object || (!value.constructor && typeof value === 'object'))
}
Enter fullscreen mode Exit fullscreen mode

Note: To validate other types, the only caveat is the same as that of Object.prototype.toString.call(), concerning the type returned, whether the value is created as a primitive or using a constructor with the new keyword.

Alternative approaches for validating object values

There are also other strategies to check if a value is an object like:

  • Object.prototype.valueOf.call(value)):

It throws Uncaught TypeError for null and undefined

  • value.--proto--:

Deprecated

  • Object.getPrototypeOf(value).isPrototypeOf(Object)
  • Object.prototype.isPrototypeOf(value)

Top comments (0)