3

After testing out instasnceof I found that it will return true if the argument is an array or an object literal.

function test(options){
  if(options instanceof Object){alert('yes')}//this will alert for both arrays and object literals
}
test({x:11})// alerts
test([11])// alerts as well but I do not want it to

Is there a way to test if the argument "options" is an object literal?

P.S. I am creating a module that will allow the user to access its configuration options, and I want to test if the argument is only an object literal or not?

Mahdi Alkhatib
  • 1,954
  • 1
  • 29
  • 43
zero
  • 2,999
  • 9
  • 42
  • 67
  • 1
    "Object literal" is just a syntax for creating objects. I assume you're trying to specifically distinguish between an Array object and a non-Array object. I'm certain this has been covered on SO. –  May 24 '12 at 16:33
  • 1
    [Distinguish between array and hash in javascript with typeof()](http://stackoverflow.com/questions/6844981/distinguish-between-array-and-hash-in-javascript-with-typeof) –  May 24 '12 at 16:36

4 Answers4

12

is there a way to test if the argument "options" is an object literal?

No, because it makes no sense. You can test whether it's an object, but how it was created (via a literal in the call to your function, via a literal elsewhere, through new Object, by deserializing a JSON string, ...) is not information that's maintained.

after testing out instasnceof i found that it will return true if the argument is an array or an object literal

Correct. Arrays in JavaScript are objects (and not really arrays).

If you want to test that an object is a plain old object, you can do this:

if (Object.prototype.toString.call(options) === "[object Object]") {
    // It's a plain object
}

But there's really no reason to do that. It's not your problem. As long as what they pass you has the properties you expect, don't try to limit the object further.

p.s. i'm making a module that will allow the user to pass it configuration options and i want to test to make sure that the argument is only an object literal.

Why? If the user wants to use an object that hasn't been declared as a literal right there and then, why would you care? If they want to use an object that they've created via a different constructor function (e.g., rather than just a plain object), again, why would you care?

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • so then i should be checking for properties and if they have values or not instead of what the argument is? – zero May 24 '12 at 16:39
  • 1
    @codewombat: Yes, that's it exactly. Just test for the things you want to see. (This is sometimes called "duck typing" -- e.g., does it walk like a duck, and quack like a duck? Then it's a duck.) – T.J. Crowder May 24 '12 at 16:40
  • I wouldn't say that arrays in JavaScript are not Arrays... But they are Objects, too. – Bergi May 24 '12 at 16:42
  • @Bergi: I didn't say they weren't Arrays, I said they weren't arrays (lower case). See the link for an explanation of why I say that. – T.J. Crowder May 24 '12 at 16:43
  • 1
    excellent answer. i'm trying to do more advance things with javascript before delving into another language i want to make sure my "P's and Q's" (i.e. best/correct practices) are straight before proceeding and this diffidently helped with that. – zero May 24 '12 at 16:49
  • don`t try to limit the object further is good but curious advice – Tegra Detra Mar 09 '17 at 22:32
2
function isPlainObject(o) {
     return Object(o) === o && Object.getPrototypeOf(o) === Object.prototype;
}

However, you can't test wether o was declared as a literal or instantiated somehow else - you can just test whether it's a plain object without any constructor than Object.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • 1
    Not that I personally care, but this does not work when testing a value passed across frames/windows. – Phrogz May 24 '12 at 16:38
  • Yes, that's true. However you can't test such an object anyway, can you? – Bergi May 24 '12 at 16:40
  • Yes, [you can](http://perfectionkills.com/instanceof-considered-harmful-or-how-to-write-a-robust-isarray/) but it's reasonably horrific: `function isArray(o) { return Object.prototype.toString.call(o) === '[object Array]'; }` – Phrogz May 24 '12 at 16:42
  • I know that one, but how would you code `isObject`? Oh, wait, `Object.getPrototypeOf(Object.getPrototypeOf(o))=== null` should work - much more horrible than the toString-trick :-) – Bergi May 24 '12 at 17:05
  • No, just replace `Array` in the string-based version with `Object`. – Phrogz May 24 '12 at 17:17
  • No, that would be true for every non-Array- and non-Host-Object - we want *plain* objects. – Bergi May 24 '12 at 17:20
  • `[ 42, "foo", /bar/, true, {}, [], new Date, undefined, Math, function(){}, new Error ].map(function(o){ return {}.toString.call(o) }).join(' '); --> "[object Number] [object String] [object RegExp] [object Boolean] [object Object] [object Array] [object Date] [object Undefined] [object Math] [object Function] [object Error]"` – Phrogz May 24 '12 at 19:19
  • You forgot `new (function x(){})` -> `[object Object]` - oops. – Bergi May 24 '12 at 19:23
  • No, in here I'm instantiating a new object from an anonymous constructor - resulting in a non "plain object" – Bergi May 24 '12 at 19:32
  • Oh, I failed to see the `new` operator. I see, you think it's somehow important to differentiate an object whose `__proto__` is `Object.prototype` from a separate one. I'm not sure why, but I understand your argument, now. – Phrogz May 24 '12 at 19:34
1

If you're trying to forbid arrays, you can just do this:

var isObject = options instanceof Object;
var isArray = options instanceof Array;
if(isObject && !isArray)
{
    alert('yes');
}
Paul Phillips
  • 6,093
  • 24
  • 34
0

An alternative solution would be to use Lodash:

_.isPlainObject(value)

Here is the documentation: https://lodash.com/docs/4.17.15#isPlainObject

James Porter
  • 158
  • 1
  • 6