0

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)

mesqueeb
  • 5,277
  • 5
  • 44
  • 77

2 Answers2

2

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)));
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • gotta modify your answer a little bit because `obj` can be `null`: `const isPlainObject = obj => obj && obj.constructor === Object && Object.getPrototypeOf(obj) === Object.prototype;` – BraveVN Oct 05 '18 at 03:09
0

it can be tricky as some javascript types have a typeof "object" like below

console.log(typeof []) // object
console.log(typeof null) // object

A simple way to check for a plain Object is to utilize Object's toString method and also validate for null like this

/**@return boolean */
function isObject(val) {
   const _toString = Object.prototype.toString;
   return val !== null && _toString.call(val) === '[object Object]';
}

now we test this

isObject({}); // true
isObject({a: 2, b: 3}); // true
isObject(null); // false
isObject([]); // false
isObject(new Object()); // true
isObject(new Array()); // false
jsdev
  • 672
  • 6
  • 14