11

I have a function I need to pass an object to. I use typeof operator to make a check before processing. But looking at this link, it appears that many javascript instances, such as array or regex, are typed as Objects.

I need my argument to be a pure object (like this : {key: value, . . .}).

Is their any way I can check if a variable is pure object, without having to run specific test for each Object instance, like Array.isArray() ?

6
  • 1
    Have a look at this extensive answer about what makes up a plain object. "I need my argument to be a pure object" - why? Your function should not need to care. Commented Jul 26, 2019 at 21:29
  • 1
    Would Boolean(obj) && obj.constructor === Object be good enough for you, knowing that even objects that are instances of any class wouldn’t be matched? Commented Jul 26, 2019 at 21:30
  • 3
    how about Object.getPrototypeOf(variable) === Object.prototype Commented Jul 26, 2019 at 21:33
  • @Bergi False! What if you need to distinguish between a plain javascript object, and things like HTMLElement, SVGElement, a Date object, a Node object, etc... "Your function should not need to care" is a very judgmental statement, considering that your contract may specify, "If the argument is a plain object, do X, otherwise do Y"! Commented Jun 20, 2020 at 3:09
  • @Michael Yes, I judge that a good API contract should not look like that, distinguishing things by the plain-ness of an object is a bad idea. Do you have an actual use case? If you want to find a HTMLElement (etc), you can use instanceof. The "plain object" is the else case. Commented Jun 20, 2020 at 13:16

6 Answers 6

21

To achieve expected result, use below option of finding constructor name to check if variable is pure javascript Object or not

As per MDN,

All objects (with the exception of objects created with Object.create(null)) will have a constructor property. Objects created without the explicit use of a constructor function (i.e. the object and array literals) will have a constructor property that points to the Fundamental Object constructor type for that object.

Please refer this link for more details on constructor property - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor

var x = {a:1,b:2};
var y = [1,2,3];

console.log(x.constructor.name === "Object")//x.constructor.name is Object
console.log(y.constructor.name === "Object")//y.constructor.name is Array

Sign up to request clarification or add additional context in comments.

2 Comments

this fails for values like {constructor: 1}
Also fails (and throws an exception) if the value you're testing is null or undefined.
16

You can check prototypes:

function isPureObject(input) {
  return null !== input && 
    typeof input === 'object' &&
    Object.getPrototypeOf(input).isPrototypeOf(Object);
}

console.log(isPureObject({}));               // true
console.log(isPureObject(new Object()));     // true
console.log(isPureObject(undefined));        // false
console.log(isPureObject(null));             // false
console.log(isPureObject(1));                // false
console.log(isPureObject('a'));              // false
console.log(isPureObject(false));            // false
console.log(isPureObject([]));               // false
console.log(isPureObject(new Array()));      // false
console.log(isPureObject(() => {}));         // false
console.log(isPureObject(function () {}));   // false
console.log(isPureObject(new Date()));       // false
console.log(isPureObject(new RegExp()));     // false

3 Comments

I found this very useful @falinksy to aid in recursive walking along object properties
Here's what I ended up with: stackoverflow.com/questions/41221672/…
function myFunction (){ /* ... */ } test it isPureObject(myFunction) and will return true
5

the shortest version

const isObj = o => o?.constructor === Object;

found here: https://stackoverflow.com/a/61684890/7138254

Comments

3

If you just want to check for "normal" pure objects (the ones created by {...}, JSON.parse(...), etc.), then this function will work

function is_pure_object(val) {
   return val ? Object.getPrototypeOf(val)==Object.prototype : false
}

If you also need to handle objects without a prototype (very rare, only created by Object.create(null)), then you need to do an additional check:

function is_pure_object2(val) {
   if (!val)
      return false
   let proto = Object.getPrototypeOf(val)
   return proto == Object.prototype || proto == null
}

Notes about other solutions:

  • Checking val.constructor is not reliable:
    • fails on values like {constructor: 1}
    • fails on Object.create(null)
    • error if Object.prototype.constructor is modified
  • Object.getPrototypeOf(val).isPrototypeOf(Object) is also not ideal:
    • error on Object.create(null)
    • error if Object.prototype.isPrototypeOf is modified

(Object.prototype being modified is unlikely, but I've dealt with it before)

Comments

0

Detection of a plain object is a bit problematic because of the definition of "plain" or "pure". I use the following method to detect plain objects. I never use x instanceof NodeList type validations because they do not work on cross-frame situations. (each window or frame has its own instance)

I think this is the simplest and most effective way of detecting plain objects.

function isPlainObject(o) {    
    var c = Object.prototype.toString.call(o) == '[object Object]'
        && o.constructor && o.constructor.name=="Object";
    return c === true;
}

function myTestFunction(){
/* ... */
}

class myTestClass{
/* ... */
}
        
console.log( isPlainObject({"a":1,"b":2}) ); //true
console.log( isPlainObject({}) ); //true
console.log( isPlainObject(null) ); //false
console.log( isPlainObject("my string") ); //false
console.log( isPlainObject("") ); //false
console.log( isPlainObject([1,2,3]) ); //false
console.log( isPlainObject(document.querySelectorAll("*")) ); //false
console.log( isPlainObject(new RegExp(/[a-z]+/)) ); //false
console.log( isPlainObject(myTestFunction) ); //false
console.log( isPlainObject(new myTestFunction()) ); //false
console.log( isPlainObject(myTestClass) ); //false
console.log( isPlainObject(new myTestClass()) ); //false

5 Comments

return c === true ? true : false; can be simplified to just return c === true;
@flinsky during some tests on many browsers I noticed it sometimes return undefined or null instead of false when null and undefined values tested. So I added it to make sure it only returns true or false. And yes return c === true is a better way. I edited it. Thanks.
also using this condition typeof o === 'object' is a little bit redundant in the context of your implementation (as soon as you're relying on the .toString implementation) see more in tc39.es/ecma262/#sec-object.prototype.tostring
@fallinsky it is for to make the evaluation more efficient. Non-object values will immediately return false after first evaluation. The following checks are more expansive.
Just keep in mind that in general, premature optimization is not something you should strive for by default. Unless you explicitly make (ideally) real measures for a more or less known or expected data set (or at least know the nature or restrictions for the data) - you don't really know what will be really more efficient. For example, consider executing this function for a set of 1000000 arrays or just null - this typeof o === 'object' will result in 1000000 unnecessary checks.
-1

Using the lodash library, you can achieve this with the following function:

const isPureObject = _.isPlainObject({ foo: 'Zebra' });
expect(isPureObject).to.be.true;
    
const isMapPureObject = _.isPlainObject(new Map());
expect(isMapPureObject).to.be.false;

The official docs can be found here.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.