9

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() ?

KawaLo
  • 1,783
  • 3
  • 16
  • 34
  • 1
    Have a look at [this extensive answer](https://stackoverflow.com/a/15322968/1048572) about what makes up a plain object. "*I need my argument to be a pure object*" - why? Your function should not need to care. – Bergi Jul 26 '19 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? – Marouane Fazouane Jul 26 '19 at 21:30
  • 3
    how about `Object.getPrototypeOf(variable) === Object.prototype` – Gabriele Petrioli Jul 26 '19 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"! – Michael Jun 20 '20 at 03: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. – Bergi Jun 20 '20 at 13:16
  • There are legitimate uses for this. For example, when processing data for `XMLHttpRequest`/`fetch`, I wanted to convert pure objects into JSON without interfering with other types (FormData, etc.) – 12Me21 Mar 09 '22 at 23:07

6 Answers6

19

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
Lee Taylor
  • 7,761
  • 16
  • 33
  • 49
Naga Sai A
  • 10,771
  • 1
  • 21
  • 40
12

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
brandonscript
  • 68,675
  • 32
  • 163
  • 220
falinsky
  • 7,229
  • 3
  • 32
  • 56
  • 1
    I found this very useful @falinksy to aid in recursive walking along object properties – King Friday Jan 17 '20 at 16:06
  • Here's what I ended up with: https://stackoverflow.com/questions/41221672/extract-only-values-from-json-object-in-javascript-without-using-a-loop/59791420#59791420 – King Friday Jan 17 '20 at 16:46
  • `function myFunction (){ /* ... */ }` test it `isPureObject(myFunction)` and will return `true` – Zortext Sep 26 '20 at 10:03
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)

12Me21
  • 992
  • 10
  • 22
2

the shortest version

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

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

Igor Sukharev
  • 2,467
  • 24
  • 21
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
Zortext
  • 566
  • 8
  • 21
  • `return c === true ? true : false;` can be simplified to just `return c === true;` – falinsky Sep 26 '20 at 10:08
  • @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. – Zortext Sep 26 '20 at 10:20
  • 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 https://tc39.es/ecma262/#sec-object.prototype.tostring – falinsky Sep 26 '20 at 10:56
  • @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. – Zortext Sep 26 '20 at 11:49
  • 1
    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. – falinsky Sep 26 '20 at 16:51
0

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.

technik
  • 1,009
  • 11
  • 17