Search code examples
javascriptclassobjectprototypeproto

How to check if an object is a regular object in JavaScript


I have a created a merging library that merges objects recursively. Sometimes in the middle there would be an object that is actually a special class (like the Timestamp of Firestore).

In my merging function I check if something is an object or not like so:

function isObject (payload) {
  const getType = Object.prototype.toString.call(payload).slice(8, -1)
  return getType === 'Object'
}

However, with this check some special classes with special prototypes are still considered to be regular JavaScript objects.

My problem:
The object will loose its special class prototype because I only go through the non-prototype values to recursively merge.

My question:
How can I change the function above to not only check if it's a JavaScript object, but also check if it's a regular JavaScript object?

Basically I only wanna return true on isObject(obj) if obj is an object like so: {} or with any props.

But once the prototype is different (and thus it's a special class), then I want to return false on isObject(obj)


Solution

  • In addition to checking the prototype, you can check if its constructor is Object:

    const isPlainObject = obj => obj.constructor === Object && Object.getPrototypeOf(obj) === Object.prototype;
    
    const obj1 = { foo: 'bar' };
    const obj2 = new Date();
    const obj3 = [];
    [obj1, obj2, obj3].forEach(obj => console.log(isPlainObject(obj)));

    Note that using getPrototypeOf and checking that it is === to Object.prototype is more reliable than using toString - toString may return anything, after all.

    If you're going to possibly pass something that's null or undefined to isPlainObject, then of course include a check to see that the obj is truthy before trying to access properties on it:

    const isPlainObject = obj => obj && obj.constructor === Object && Object.getPrototypeOf(obj) === Object.prototype;
    
    const obj1 = { foo: 'bar' };
    const obj2 = new Date();
    const obj3 = [];
    [obj1, obj2, obj3].forEach(obj => console.log(isPlainObject(obj)));