3

Given the developments of JavaScript since the languages' inception, why is there not a built in method that checks if an object is a plain object?

Or does the method in fact exist?

guest271314
  • 1
  • 15
  • 104
  • 177
  • If I understood correctly I think `instance of` is one way. – Mritunjay Nov 07 '16 at 01:21
  • 4
    What exactly are you asking? What does *an object is "`[object Object]"`* mean in practical terms? – Pointy Nov 07 '16 at 01:23
  • "[object Object]" is just the output of `Object.prototype.toString` with *any* object as an argument. – Tibrogargan Nov 07 '16 at 01:24
  • @Pointy Consider filtering an array `let arr = [1,2,true,4,{"abc":123},6,7,{"def":456},9,[10],{},"[object Object]"];` where expected result is matching `[{"abc":123},{"def":456},{}];`, but not string `"[object Object]"`. Related http://stackoverflow.com/questions/40455880/what-is-the-briefest-javascript-necessary-to-filter-objects-from-an-array – guest271314 Nov 07 '16 at 01:26
  • based from my understanding of your question, this would do it `myObj instanceof Object` – Barak Nov 07 '16 at 01:27
  • @guest `typeof "[object Object]"` is "string" – Tibrogargan Nov 07 '16 at 01:27
  • @guest271314 Well for one thing note that `1`, `2`, `true`, and `4` are not objects in any sense. That string "[object Object]" is the output from `Object.prototype.toString()` when applied to an object of some type. – Pointy Nov 07 '16 at 01:29
  • @Tibrogargan Yes. That string should not be matched. – guest271314 Nov 07 '16 at 01:29
  • @Pointy Yes, included string to not match string. – guest271314 Nov 07 '16 at 01:30
  • @guest271314 so ... filter it. Everything else in your array is "boolean", "object" or "number" – Tibrogargan Nov 07 '16 at 01:30
  • @Barak `[] instanceof Object` matches arrays as well, not only `{}` – guest271314 Nov 07 '16 at 01:30
  • https://jsfiddle.net/cx0mnuod/ – Ram Nov 07 '16 at 01:31
  • @Tibrogargan The actual Question is why a built in method does not exist, or perhaps does, that only filters `{}`, not `{}` and `[]` when attempting to match only `{}`. A comparison would be `Array.isArray` – guest271314 Nov 07 '16 at 01:32
  • Right - `Object.prototype.toString.call("[object Object]")` returns "[object String]", which is weird but at least it's different from "[object Object]". – Pointy Nov 07 '16 at 01:32
  • Possible duplicate of [Check if a value is an object in JavaScript](http://stackoverflow.com/questions/8511281/check-if-a-value-is-an-object-in-javascript) – Thilo Nov 07 '16 at 01:33
  • @undefined Yes. Found a solution using approach at related Question. Present Question is why the method does not exist as a build in method of `JavaScript`, similar to `Array.isArray`? – guest271314 Nov 07 '16 at 01:33
  • 3
    Questions of the form "why does language X have/lack feature Y" are best directed at language implementors. JavaScript doesn't have *lots* of things. – Pointy Nov 07 '16 at 01:33
  • 1
    The question isn't relevant to the previous question. `[] instanceof Object` matches arrays because they *are* objects and prototypically inherit from Object. If you're relatively new to JS, this may take some time to get accustomed to the idea of prototypical inheritance. Then `o instanceof Object && Array.isArray(o)` should make perfect sense (btw, it doesn't cover `Object.create(null)`). – Estus Flask Nov 07 '16 at 01:34
  • @guest271314 No, that's not the original question. Perhaps you could rephrase it like that? That makes a lot more sense than using the output of toString to imply an object vs an array – Tibrogargan Nov 07 '16 at 01:35
  • @Thilo How is present Question a duplicate? Which Answer affirmatively answers present Question? – guest271314 Nov 07 '16 at 01:36
  • @Pointy Well, began here. With those that implement the language. Considering that a sage of the language might be aware of the Answer. – guest271314 Nov 07 '16 at 01:40
  • @estus Not sure if related or not to previous Question, but incidentally the exchange there between you and this user led to the current Question being presented. Actually find it fascinating that such a specific built in method, appears to, not exist; given the many developments of the language since its inception. – guest271314 Nov 07 '16 at 01:42
  • That's not a valid dupe! – Praveen Kumar Purushothaman Nov 07 '16 at 01:53
  • When I find that some platform does not support a feature I think is obviously of great usefulness, sometimes I start to wonder whether I've made some conceptual or philosophical mistakes along the way of learning about the platform. – Pointy Nov 07 '16 at 01:53
  • The question in this state is somewhat offtopic ('why' is rhetorical). But there's no built-in method is because the requirement is really specific. Almost always not only plain objects but class instances should be acceptable as well. If the requirement changes to 'every object except built-ins like Array and RegExp', it is always as easy as writing a helper function (or using existing one). – Estus Flask Nov 07 '16 at 02:10
  • @estus Updated Question to use term "plain object". Am actually a novice user of `JavaScript`, here. "Why" is not rhetorical. Why is directly seeking Truth. The root of the matter. – guest271314 Nov 07 '16 at 02:16

5 Answers5

4

You can check the type and the instance of an object this way:

var a = new Date();
console.log(typeof a);
console.log(a instanceof Date);

var b = "Hello";
console.log(typeof b);
console.log(b instanceof Date);

Updated according to the comments from the OP:

let arr = [1, 2, true, 4, {
    "abc": 123
  },
  6, 7, {
    "def": 456
  },
  9, [10], {}, "[object Object]"
];
arr.forEach(function(v) {
  if (typeof v == "object" && !(v instanceof Array) && v != null)
    console.log("Object Found");
  else
    ; // console.log("Na");
});

The above code snippets outputs thrice Object Found.

Praveen Kumar Purushothaman
  • 164,888
  • 24
  • 203
  • 252
  • `typeof` is inappropriate here. Because of `null`. – Estus Flask Nov 07 '16 at 01:24
  • @estus We can also check for null values by adding, `&& a != null`. Do you want me to add it or? – Praveen Kumar Purushothaman Nov 07 '16 at 01:25
  • 1
    I guess this would answer the question accurately. – Estus Flask Nov 07 '16 at 01:28
  • 1
    `instanceof` matches arrays as well, not only `{}` `"[object Object]"` – guest271314 Nov 07 '16 at 01:29
  • @guest271314 What are you trying to match? – Praveen Kumar Purushothaman Nov 07 '16 at 01:29
  • @guest271314 Now I understood. You can try eliminating like... Hey, use the prototype may be... So, `.__proto__` will give `Object` or `Array` based on stuff. – Praveen Kumar Purushothaman Nov 07 '16 at 01:33
  • @PraveenKumar Can you demonstrate what you are describing? That is matching `"[object Object]"` from `let arr = [1,2,true,4,{"abc":123},6,7,{"def":456},9,[10],{},"[object Object]"];`, which should result in three elements being matched? Does `{}` or `Object.create(null)` have a `.__proto__`? – guest271314 Nov 07 '16 at 01:38
  • @guest271314 Sure, definitely. – Praveen Kumar Purushothaman Nov 07 '16 at 01:39
  • 1
    @PraveenKumar Yes. Your Answer returns expected result. Why is there not a built in `JavaScript` method to check if an object is `"[object Object]"`? – guest271314 Nov 07 '16 at 01:48
  • 1
    @guest271314 Er... `:)` I didn't develop JavaScript. Ha ha... Actually, this could be posed to the JavaScript Working Group. Good idea mate. If not you, I am gonna post it soon. – Praveen Kumar Purushothaman Nov 07 '16 at 01:50
  • @PraveenKumar fwiw, the approach that returns same expected result http://stackoverflow.com/questions/40455880/what-is-the-briefest-javascript-necessary-to-filter-objects-from-an-array? Do you have link to JavaScript Working Group? How do you intend to phrase the Question? Plain and direct: "Why is there not a built in method to check if an object is `"[object Object]"`?" – guest271314 Nov 07 '16 at 01:51
  • 1
    @guest271314 I am not sure. Will have a look for you... `:)` – Praveen Kumar Purushothaman Nov 07 '16 at 01:55
  • 1
    @PraveenKumar Ok. Want to formulate the Question properly; to avoid confusion and try to get accurate Answer. – guest271314 Nov 07 '16 at 02:00
  • @PraveenKumar Asked a previous Question which actually tried to get to the root of the matter, but was perceived in a different way. As if the Question was some sort of "code golf" Question. Tried to be plain and clear at present Question. The present Question is actually "Why such a method does not exist. That is, why is there no built in method which specifically checks if an object is a plain object?" Does your Answer affirmatively resolve this Question? – guest271314 Nov 07 '16 at 02:20
  • @guest271314 I don't think any of the answer qualifies and none of us can answer your question straight as we are not the people who design JavaScript, but just experts at it, like you. So... :) – Praveen Kumar Purushothaman Nov 07 '16 at 02:21
  • @PraveenKumar Yes. Agree. Though, not an expert, here; rather a novice. The Answer must be available. From point of view, here, once the facts have been obtained, the correct Answer to the actual Question should be accepted. – guest271314 Nov 07 '16 at 02:26
  • 1
3

There doesn't exist any explicit direct way to check if a value is an object, i.e. belongs to Object type, but there are some foolproof ways to do it. I wrote a list in another answer, the most succinct seems

function isObject(value) {
  return Object(value) === value;
}

A feature like this has been requested multiple times on esdiscuss. For example,

In fact, Object.isObject was proposed as strawman, and it appeared in an ES6 early draft.

Object.isObject strawman was eventually rejected and removed from ES6 draft.

More recently,

Now there is the is{Type} Methods stage 0 proposal which includes Object.isObject among lots of various other checks.

So there is still hope and eventually we may have something like this.


The above is for testing objects in general. If you don't want that you should define what "plain object" means for you.

For example, you can test the constructor property. But any object can customize it.

You can use Object.prototype.toString to get the legacy ES5 [[Class]]. But any object can customize that via Symbol.toStringTag.

You can check the value returned by [[GetPrototypeOf]]. But even exotic objects might allow their prototype to be changed to whatever arbitrary object or null. And Proxy objects even have full control over that internal method.

So most probably you won't be able to rely on these tests. And adding something to the standard may be hard because different people may want different things.

What I would like is some way to check if an object is an ordinary one. That is, it has the default behaviour for the essential internal methods that must be supported by all objects.

Once you know that an object is ordinary, you can rely on things like [[GetPrototypeOf]] to customize the test to your tastes.

Community
  • 1
  • 1
Oriol
  • 274,082
  • 63
  • 437
  • 513
  • 3
    Note, `Object` can be assigned as an identifier. `Object = 1; Object(1) === 1;` `Uncaught TypeError: Object is not a function`, `Object === 1 // true` – guest271314 Nov 15 '16 at 00:58
  • 1
    @guest271314 In my list of ways to check if a value is an object there is an approach which does not require a sane environment: `new function() { return value; }() === value` – Oriol Nov 15 '16 at 02:48
  • Not certain how the pattern is used? Have been attempting to determing if a particular pattern is possible. Check if element is plain object is part of process. Other part is pattern itself. http://stackoverflow.com/questions/36232576/how-to-filter-object-using-array-prototype-filter , http://stackoverflow.com/questions/40541169/how-to-call-function-that-is-parameter-to-function-prototype-bind-with-value-pas – guest271314 Nov 15 '16 at 02:53
  • Have been trying `Object.is()`. `Object.getPrototypeOf()` , `Object.isPrototypeOf()` throw error when value is `undefined`.Can chain `.map()` calls though will have to convert back to original value, requiring extra calls `arr.map(Object).map(Object.getPrototypeOf).filter(Object.is.bind(null, Object.prototype))` – guest271314 Nov 15 '16 at 02:59
  • @guest271314 I don't get what you are attempting to achieve. `Object` doesn't throw when the argument is not an object because it coerces to Object type. The methods expect an object so they throw. – Oriol Nov 15 '16 at 03:20
  • `Object` function can be assigned to a different value.. https://jsfiddle.net/ze446o2e/ . Adding another element to consider, here. – guest271314 Nov 15 '16 at 03:30
  • 1
    Trying to pass a function reference as a callback function which calls its own bound function with the value passed as parameter to original function call, then calls parameter function with same value before returning result. E.g., `arr.filter(Object.is.bind(null, Object.prototype, Object.getProtototypeOf /* pass current element of `arr` to Object.getProtototypeOf then call */))`, or similar pattern, without explicitly using `function(element, index, thisArg){}`; using only bound function references which are passed the current value. Or, determine if the pattern cannot be achieved. – guest271314 Nov 15 '16 at 03:33
  • 1
    This doesn't work for arrays as it returns true even though an array is not a plain javascript object. – KhalilRavanna Dec 03 '21 at 17:16
2

Relying on [object Object] string representation is inaccurate. This behaviour may be changed for any objects with:

let o = { toString: () => '...' };
('' + o) !== '[object Object]'

var a = [];
a.toString = () => '[object Object]';
('' + a) === '[object Object]';

The most solid way to check if a value is a plain object is

let o = {}
Object.getPrototypeOf(o) === Object.prototype

And considering that constructor property wasn't tampered, the most straightforward way to check if a value is a plain object is

let o = {}
o.constructor === Object

This covers all POJOs constructed from Object and doesn't cover Object.create(null, { ... }) or any child classes (including built-ins like RegExp or Array):

Object.create(null).constructor !== Object
[].constructor !== Object
(new class {}).constructor !== Object

One of the possible reasons why there is no dedicated method to check for object plainness is because a restriction to use only {} objects is not practical. This makes very little sense in the context of JS. This prevents the use of any class instances or relatively 'plain' objects (Object.create({}, ...)).

This would require the hack in order for desired non-plain objects to pass the check:

Object.assign({}, (new class {})).constructor === Object

In most cases of object checking 'everything which is not forbidden is allowed' principle pays off (with extra caution regarding infamous null inconsistency).

Applying the above to this case, a safe and concise condition to filter non-array objects is

o && typeof o === 'object' && !Array.isArray(o)

And a condition to filter objects that are not built-ins (functions, Array, RegExp, etc) is

o && (o.constructor === Object || !/\[native code\]/.test(o.constructor))
Community
  • 1
  • 1
Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • What does "POJOs" mean? _"and doesn't cover"_ Can you provide examples of what is _not_ covered by the approach at Answer? That is Question. Why is there not a method that specifically checks for `"[object Object]"`, that is, a plain object? Can you also elaborate on why checking for `"[object Object]"` is not reliable? Not sure gather first example entirely, here. – guest271314 Nov 07 '16 at 01:54
  • 1
    Plain Old JavaScript Object (adopted from Java). An informal term for `{}` objects (may or may not cover non-Object `Object.create(null, { ... })` objects, depending on the context. – Estus Flask Nov 07 '16 at 01:58
  • How does your Answer answer Question of why a built-in method does not exist that checks if an object is a plain object? Can you describe how checking for `"[object Object]"` would fail for first example at your Answer? – guest271314 Nov 07 '16 at 02:02
  • Good to be aware of. Does this fact, relating to the unreliability of checking for `"[object Object]"` not nullify the proposition that previous Question is one concerning "code golf"? But, rather, why do users of the language currently have no single reliable method to achieve the expected result; but need to put together different methods to be certain that only plain objects are returned? As that is what was attempting to convey. – guest271314 Nov 07 '16 at 02:10
  • @guest271314 I've updated the answer with remark on object prototype. As I already said in the comment, there generally shouldn't be a restriction to use only `{}` objects. This makes very little sense in the context of JS and OOP. Not so long ago I've had to fix some Node lib because it was allowed only POJOs, but didn't allow `Object.create({}, ...)` object which was emitted by Node (it passes `constructor` check but doesn't pass `getPrototypeOf()` check). – Estus Flask Nov 07 '16 at 02:35
  • _"As I already said in the comment, there generally shouldn't be a restriction to use only {} objects. This makes very little sense in the context of JS and OOP."_ That is an important point had considered. Can you include the description of your experience with, and implications relating to this topic within your Answer? Are you referencing the first example `javascript` at your Answer? – guest271314 Nov 07 '16 at 02:47
  • Is that the reason there does not exist a single method to check for a plain object? – guest271314 Nov 07 '16 at 02:52
  • 1
    I've updated the question to cover the previous question. The reason is that such method is just generally not needed. The restriction to use a plain object can hardly be justified, and 'everything which is not forbidden is allowed' principle pays off. If a dev ever needs something specific condition to match, he/she has usually got a fair amount of fingers to write some helper function or [use an existing one](http://api.jquery.com/jquery.isplainobject/) (or [two](https://www.npmjs.com/package/is-plain-obj)). – Estus Flask Nov 07 '16 at 03:37
  • `res = arr.filter(o => Object.getPrototypeOf(o) === Object.prototype)` does in fact appear to filter plain objects. Is there a way to pass only `Object.getPrototype` as a function reference to `.filter()` , with `thisArg` set to `Object.prototype`, or other pattern, to be able to write `.filter(Object.getPrototypeOf)`? http://stackoverflow.com/questions/36232576/how-to-filter-object-using-array-prototype-filter/ – guest271314 Nov 07 '16 at 20:24
  • No, there's no way. I'm not sure what are your concerns, but that's what predicates are for. If you expect the function to be used in multiple places, you can move this predicate (or the whole `.filter(...)` part) to a helper function and import it whenever needed. – Estus Flask Nov 07 '16 at 20:38
  • _"No, there's no way."_ Is conclusive Answer. Have provided similar response in relation to accessing `.value` of `` element at `user-agent` `ShadowDOM` which renders `Choose File` or `Browse..` until found that chromium does provide that value of `` at `.computedName` property of `type="file" http://stackoverflow.com/a/40293559/. That is, no known way as of yet, until a way is found, then it will be known. Curious why `Object.create()` does not meet condition `Object.getPrototypeOf(o) === Object.prototype`? – guest271314 Nov 07 '16 at 23:23
  • Is the reason because `Object.create` `prototype` is `undefined`, though `constructor` is `function create()`? – guest271314 Nov 07 '16 at 23:39
  • 1
    There's no way *for now*. And it is unlikely that this will be changed in future because *direct* parentage checking is very low profile and it causes more problems than it solves - this is just against JS nature. And fortunately, it is something that can be done with a single line of code. There's nothing special about `Object.create` it self. The special cases are `Object.create(null)` (object prototype is `undefined), `Object.create({})` (object prototype is another object)... actually, anything but `Object.create(Object.prototype)`. – Estus Flask Nov 07 '16 at 23:42
  • Ok. Got it. Was omitting the fact that first parameter to `Object.create()` is the `prototype` of the created object. `Object.create(Object.prototype, {abc:{value:null}})` does meet condition at `.filter()` callback. – guest271314 Nov 07 '16 at 23:48
  • Yes, that's how object literals are usually mimicked with `Object.create` – Estus Flask Nov 07 '16 at 23:50
  • `Object.is()` appears to return expected result where one parameter is `Object.prototype` and `.__proto__` is chained to target object. – guest271314 Nov 08 '16 at 01:54
  • 1
    `__proto__` is is unstandardized. `===` does the job, `Object.is` is excessive here (it is `===` with benefits). – Estus Flask Nov 08 '16 at 01:59
  • Note `const o = void 0; Object.getPrototypeOf(o) === Object.prototype` logs `Uncaught TypeError: Cannot convert undefined or null to object` – guest271314 Nov 15 '16 at 00:13
  • Yes, notice that there are `o && ...` checks in several places in the answer, they are necessary for unverified input. – Estus Flask Nov 15 '16 at 00:30
-1

Just for the sake of further documenting different ways:

One way I can think of:

JSON.stringify(testValue)[0] === '{';

Keep in mind that objects with circular references cannot be stringified. However, if you are certain that all testValues cannot have circular references, you have yourself a way to check against Null, Arrays, and any primitive value to ensure that you have an Object.

I suggest that if you plan on using this throughout your code though, that you define a helper function that actually implements it, in case you find that this does not work as you expect and end up having to change the way you check it.

santanaG
  • 120
  • 6
-3

Every thing JavaScript is an Object , so there is no need to have an isObject api

Raaghu
  • 1,956
  • 1
  • 19
  • 17
  • That is not true: `2`, `true`, `"hello"`, `undefined`, `null`, `NaN` are all examples of values that are not objects (even though `typeof null` reports it is one). They are [primitive values](https://developer.mozilla.org/en/docs/Glossary/Primitive). – trincot Nov 07 '16 at 18:54
  • @trincot Technically, primitives are objects, i.e. instances of respective constructors (except `undefined` and `null`). But they are certainly not `Object` objects. – Estus Flask Nov 07 '16 at 20:46
  • @estus, do you have a reference for "*primitives are objects*"? Quoted from [MDN](https://developer.mozilla.org/en-US/docs/Glossary/Primitive): *"A primitive (primitive value, primitive data type) is data that is **not** an object"*. Maybe you were thinking of primitive wrapper objects? – trincot Nov 07 '16 at 20:56
  • @trincot It is less confusing to not think of them as of objects, but in fact, they are the ones, even though special ones. A statement from MDN is incorrect, *A primitive (primitive value, primitive data type) is data that is not an object and has no methods*. Primitives cannot have own methods but get the methods of their prototypes (and can gain new methods by prototype extension). `''.__proto__ === String.prototype && ''.constructor === String`. – Estus Flask Nov 07 '16 at 21:06
  • 1
    What you show at the end is an example of coercion: `''` is not an object, but JavaScript will turn it into one when you reference a property like that. Although this *seems* to prove the string literal is an object, this is not the case. Indeed, `''.__proto__` really gets parsed as `String('').__proto__`. May I invite you to read [The Secret Life of JavaScript Primitives](https://javascriptweblog.wordpress.com/2010/09/27/the-secret-life-of-javascript-primitives/) which explains this quite well. – trincot Nov 07 '16 at 21:15