ObjectconstructorThe
Objectconstructor coerces the passed argument to an object. If it's already an object, the same object is returned.Therefore, you can use it to coerce the value to an object, and strictly compare that object with the original value.
The following function requires ECMAScript 3, which introduced
===:function isObject(value) { /* Requires ECMAScript 3 or later */ return Object(value) === value; }I like this approach because it's simple and self-descriptive, and an analogous check will also work for booleans, numbers and strings. However, be aware it relies on the global
Objectnot being shadowed nor altered.Constructors
When you instantiate a constructor, it can return a value different than the just-created instance. But that value will be ignored unless it's an object.
The following function requires ECMAScript 3, which allowed constructors to return non-objects. Before ECMAScript 3 that threw an error, but
trystatements didn't exist back then.function isObject(value) { /* Requires ECMAScript 3 or later */ return new function() { return value; }() === value; }While a bit less simple than the previous example, this one does not rely on any global property, and thus might be the safest.
thisvalueOld ECMAScript specifications required the
thisvalue to be an object. ECMAScript 3 introducedFunction.prototype.call, which allowed to call a function with an arbitrarythisvalue, but coerced to an object.ECMAScript 5 introduced a strict mode which removed this behavior, but in sloppy mode we still can (but arguably shouldn't) rely on it.
function isObject(value) { /* Requires ECMAScript 3 or later in sloppy mode */ return function() { return this === value; }.call(value); }[[Prototype]]
All ordinary objects have an internal slot called [[Prototype]], whose value determines from which other object it inherits from. The value can only be an object or
null. Therefore, you can attempt to create an object which inherits from the desired value, and check if it worked.Both
Object.createandObject.getPrototypeOfrequire ECMAScript 5.function isObject(value) { /* Requires ECMAScript 5 or later */ try { Object.create(value); return value !== null; } catch(err) { return false; } }function isObject(value) { /* Requires ECMAScript 5 or later */ function Constructor() {} Constructor.prototype = value; return Object.getPrototypeOf(new Constructor()) === value; }Some new ECMAScript 6 ways
ECMAScript 6 introduces some new indirect ways to check is a value is an object. They use the previously seen approach to pass the value to some code which requires an object, wrapped inside a
trystatement to catch errors. Some hidden examples, not worth commentingfunction isObject(value) { /* Requires ECMAScript 6 or later */ try { Object.setPrototypeOf({}, value); return value !== null; } catch(err) { return false; } }function isObject(value) { /* Requires ECMAScript 6 or later */ try { new Proxy(value, value); return value; } catch(err) { return false; } }function isObject(value) { /* Requires ECMAScript 6 or later */ try { new WeakSet([value]); return value;true; } catch(err) { return false; } }
ObjectconstructorThe
Objectconstructor coerces the passed argument to an object. If it's already an object, the same object is returned.Therefore, you can use it to coerce the value to an object, and strictly compare that object with the original value.
The following function requires ECMAScript 3, which introduced
===:function isObject(value) { /* Requires ECMAScript 3 or later */ return Object(value) === value; }I like this approach because it's simple and self-descriptive, and an analogous check will also work for booleans, numbers and strings. However, be aware it relies on the global
Objectnot being shadowed nor altered.Constructors
When you instantiate a constructor, it can return a value different than the just-created instance. But that value will be ignored unless it's an object.
The following function requires ECMAScript 3, which allowed constructors to return non-objects. Before ECMAScript 3 that threw an error, but
trystatements didn't exist back then.function isObject(value) { /* Requires ECMAScript 3 or later */ return new function() { return value; }() === value; }While a bit less simple than the previous example, this one does not rely on any global property, and thus might be the safest.
thisvalueOld ECMAScript specifications required the
thisvalue to be an object. ECMAScript 3 introducedFunction.prototype.call, which allowed to call a function with an arbitrarythisvalue, but coerced to an object.ECMAScript 5 introduced a strict mode which removed this behavior, but in sloppy mode we still can (but arguably shouldn't) rely on it.
function isObject(value) { /* Requires ECMAScript 3 or later in sloppy mode */ return function() { return this === value; }.call(value); }[[Prototype]]
All ordinary objects have an internal slot called [[Prototype]], whose value determines from which other object it inherits from. The value can only be an object or
null. Therefore, you can attempt to create an object which inherits from the desired value, and check if it worked.Both
Object.createandObject.getPrototypeOfrequire ECMAScript 5.function isObject(value) { /* Requires ECMAScript 5 or later */ try { Object.create(value); return value !== null; } catch(err) { return false; } }function isObject(value) { /* Requires ECMAScript 5 or later */ function Constructor() {} Constructor.prototype = value; return Object.getPrototypeOf(new Constructor()) === value; }Some new ECMAScript 6 ways
ECMAScript 6 introduces some new indirect ways to check is a value is an object. They use the previously seen approach to pass the value to some code which requires an object, wrapped inside a
trystatement to catch errors. Some hidden examples, not worth commentingfunction isObject(value) { /* Requires ECMAScript 6 or later */ try { Object.setPrototypeOf({}, value); return value !== null; } catch(err) { return false; } }function isObject(value) { /* Requires ECMAScript 6 or later */ try { new Proxy(value, value); return value; } catch(err) { return false; } }function isObject(value) { /* Requires ECMAScript 6 or later */ try { new WeakSet([value]); return value; } catch(err) { return false; } }
ObjectconstructorThe
Objectconstructor coerces the passed argument to an object. If it's already an object, the same object is returned.Therefore, you can use it to coerce the value to an object, and strictly compare that object with the original value.
The following function requires ECMAScript 3, which introduced
===:function isObject(value) { /* Requires ECMAScript 3 or later */ return Object(value) === value; }I like this approach because it's simple and self-descriptive, and an analogous check will also work for booleans, numbers and strings. However, be aware it relies on the global
Objectnot being shadowed nor altered.Constructors
When you instantiate a constructor, it can return a value different than the just-created instance. But that value will be ignored unless it's an object.
The following function requires ECMAScript 3, which allowed constructors to return non-objects. Before ECMAScript 3 that threw an error, but
trystatements didn't exist back then.function isObject(value) { /* Requires ECMAScript 3 or later */ return new function() { return value; }() === value; }While a bit less simple than the previous example, this one does not rely on any global property, and thus might be the safest.
thisvalueOld ECMAScript specifications required the
thisvalue to be an object. ECMAScript 3 introducedFunction.prototype.call, which allowed to call a function with an arbitrarythisvalue, but coerced to an object.ECMAScript 5 introduced a strict mode which removed this behavior, but in sloppy mode we still can (but arguably shouldn't) rely on it.
function isObject(value) { /* Requires ECMAScript 3 or later in sloppy mode */ return function() { return this === value; }.call(value); }[[Prototype]]
All ordinary objects have an internal slot called [[Prototype]], whose value determines from which other object it inherits from. The value can only be an object or
null. Therefore, you can attempt to create an object which inherits from the desired value, and check if it worked.Both
Object.createandObject.getPrototypeOfrequire ECMAScript 5.function isObject(value) { /* Requires ECMAScript 5 or later */ try { Object.create(value); return value !== null; } catch(err) { return false; } }function isObject(value) { /* Requires ECMAScript 5 or later */ function Constructor() {} Constructor.prototype = value; return Object.getPrototypeOf(new Constructor()) === value; }Some new ECMAScript 6 ways
ECMAScript 6 introduces some new indirect ways to check is a value is an object. They use the previously seen approach to pass the value to some code which requires an object, wrapped inside a
trystatement to catch errors. Some hidden examples, not worth commentingfunction isObject(value) { /* Requires ECMAScript 6 or later */ try { Object.setPrototypeOf({}, value); return value !== null; } catch(err) { return false; } }function isObject(value) { /* Requires ECMAScript 6 or later */ try { new WeakSet([value]); return true; } catch(err) { return false; } }
The most reasonable way to check the type of a value seems the typeof operator. The only problem is that it's horribly broken:
- It returns
"object"fornull, which belongs to Null type. - It returns
"function"for callable objects, which belong to Object type. - It can return (almost) anything it wants for non-standard non-callable objects. For example, IE seemed to like
"unknown". The only forbidden results are"function"and primitive types.
typeof is only reliable for non-null primitives. So a way to check if a value is an object would be ensuring that the string returned by typeof does not correspond to a primitive, and that the object is not null. However, the problem is that a future standard could introduce a new primitive type, and our code would consider it to be an object. New types don't appear frequently, but for example ECMAScript 6 introduced the Symbol type.
Therefore, instead of typeof, I only recommend approaches whose result varies depending on if the value is an object or not. The following intends to be a
Comprehensive but not exhaustive list of proper ways to test if a value belongs to the Object type.
ObjectconstructorThe
Objectconstructor coerces the passed argument to an object. If it's already an object, the same object is returned.Therefore, you can use it to coerce the value to an object, and strictly compare that object with the original value.
The following function requires ECMAScript 3, which introduced
===:function isObject(value) { /* Requires ECMAScript 3 or later */ return Object(value) === value; }I like this approach because it's simple and self-descriptive, and an analogous check will also work for booleans, numbers and strings. However, be aware it relies on the global
Objectnot being shadowed nor altered.Constructors
When you instantiate a constructor, it can return a value different than the just-created instance. But that value will be ignored unless it's an object.
The following function requires ECMAScript 3, which allowed constructors to return non-objects. Before ECMAScript 3 that threw an error, but
trystatements didn't exist back then.function isObject(value) { /* Requires ECMAScript 3 or later */ return new function() { return value; }() === value; }While a bit less simple than the previous example, this one does not rely on any global property, and thus might be the safest.
thisvalueOld ECMAScript specifications required the
thisvalue to be an object. ECMAScript 3 introducedFunction.prototype.call, which allowed to call a function with an arbitrarythisvalue, but coerced to an object.ECMAScript 5 introduced a strict mode which removed this behavior, but in sloppy mode we still can (but arguably shouldn't) rely on it.
function isObject(value) { /* Requires ECMAScript 3 or later in sloppy mode */ return function() { return this === value; }.call(value); }[[Prototype]]
All ordinary objects have an internal slot called [[Prototype]], whose value determines from which other object it inherits from. The value can only be an object or
null. Therefore, you can attempt to create an object which inherits from the desired value, and check if it worked.Both
Object.createandObject.getPrototypeOfrequire ECMAScript 5.function isObject(value) { /* Requires ECMAScript 5 or later */ try { Object.create(value); return value !== null; } catch(err) { return false; } }function isObject(value) { /* Requires ECMAScript 5 or later */ function Constructor() {} Constructor.prototype = value; return Object.getPrototypeOf(new Constructor()) === value; }Some new ECMAScript 6 ways
ECMAScript 6 introduces some new indirect ways to check is a value is an object. They use the previously seen approach to pass the value to some code which requires an object, wrapped inside a
trystatement to catch errors. Some hidden examples, not worth commentingfunction isObject(value) { /* Requires ECMAScript 6 or later */ try { Object.setPrototypeOf({}, value); return value !== null; } catch(err) { return false; } }function isObject(value) { /* Requires ECMAScript 6 or later */ try { new Proxy(value, value); return value; } catch(err) { return false; } }function isObject(value) { /* Requires ECMAScript 6 or later */ try { new WeakSet([value]); return value; } catch(err) { return false; } }
Note: I intentionally skipped some approaches like Object.getPrototypeOf(value) (ES5) and Reflect methods (ES6) because they call essential internal methods which might do nasty things, e.g. if value is a proxy. For safety reasons my examples only reference value without accessing it directly.