67

I have seen two ways of detecting whether a UA implements a specific JS property: if(object.property) and if('property' in object).

I would like to hear opinions on which is better, and most importantly, why. Is one unequivocally better than the other? Are there more than just these two ways to do object property detection? Please cover browser support, pitfalls, execution speed, and such like, rather than aesthetics.

Edit: Readers are encouraged to run the tests at jsperf.com/object-detection

Nicholas Shanks
  • 10,623
  • 4
  • 56
  • 80

5 Answers5

122
  • if(object.property)

    will fail in cases it is not set (which is what you want), and in cases it has been set to some falsey value, e.g. undefined, null, 0 etc (which is not what you want).

    var object = {property: 0};
    if(object.isNotSet) { ... } // will not run
    if(object.property) { ... } // will not run
    
  • if('property' in object)

    is slightly better, since it will actually return whether the object really has the property, not just by looking at its value.

    var object = {property: 0};
    if('property' in object) { ... } // will run
    if('toString' in object) { ... } // will also run; from prototype
    
  • if(object.hasOwnProperty('property'))

    is even better, since it will allow you to distinguish between instance properties and prototype properties.

    var object = {property: 0};
    if(object.hasOwnProperty('property')) { ... } // will run
    if(object.hasOwnProperty('toString')) { ... } // will not run
    

I would say performance is not that big of an issue here, unless you're checking thousands of time a second but in that case you should consider another code structure. All of these functions/syntaxes are supported by recent browsers, hasOwnProperty has been around for a long time, too.


Edit: You can also make a general function to check for existence of a property by passing anything (even things that are not objects) as an object like this:

function has(obj, prop) {
    return Object.prototype.hasOwnProperty.call(obj, prop);
}

Now this works:

has(window, 'setTimeout'); // true

even if window.hasOwnProperty === undefined (which is the case in IE version 8 or lower).

robinCTS
  • 5,746
  • 14
  • 30
  • 37
pimvdb
  • 151,816
  • 78
  • 307
  • 352
  • 1
    I agree that performance considerations are irrelevant here (even for hundreds of thousands of comparisons, the difference is unimportant because the speed is so fast). But thinking academically, if anything `if (object.hasOwnProperty)` is the *fastest*, because it just checks the object in memory for the property. The other two have more work to do. `if ('property' in object)` has check the property in the object, but also check the prototype chain if the property is not found. `if (object.property)` has to check the property in the object, and then also do a type coercion in most cases. – Ben Lee Aug 24 '11 at 12:07
  • 4
    `object.hasOwnProperty` is dangerous if `object` is a host object because host objects are not obliged to inherit from `Object.prototype` (and indeed in IE < 9, they generally do not), so I would recommend against that one. – Tim Down Aug 24 '11 at 13:25
  • @Ben Lee: I think you're correct. However, calling functions tend to be slower in general, so I'm not entirely sure. – pimvdb Aug 24 '11 at 14:27
  • @Tim Down: Thanks, that's good to know. I will try to fiddle around to see how IE handles it. – pimvdb Aug 24 '11 at 14:28
  • 1
    @Ben Lee: It turned out to be different on Chrome: http://jsperf.com/object-detection. – pimvdb Aug 24 '11 at 15:11
  • @pimvdb, yeah I completely forgot about the cost of function calls. Anyway, out of curiosity I ran the test in some other browsers in Linux and Windows (you can see the results there). The pattern mostly holds across browsers with "object.property" way ahead of the rest and the other three somewhat close (with more or less divergence depending on the browser). The big standout exception is IE8, where oddly "object.property" is way way below the others. I feel like this may be a fluke and I probably should run the test again but don't feel like opening my VM again. It's purely academic anyway. – Ben Lee Aug 24 '11 at 16:06
  • @Ben Lee: Thanks for running in several scenarios. If even IE6 can handle 100.000+ calls a second, any performance hits are indeed negligible. – pimvdb Aug 24 '11 at 17:13
  • Would you be willing to comment on how to check for nested properties? e.g., var obj = { property1: { propertyOfProperty1: 0 } } Is the best method to use nested if statements? – bgmaster Jan 08 '15 at 12:08
10

It really depends what you want to achieve. Are you talking about host objects (such as window and DOM nodes)? If so, the safest check is typeof, which works for all host objects I know of:

 if (typeof object.property != "undefined") { ... }

Notes:

  • Avoid object.hasOwnProperty() for host objects, because host objects are not obliged to inherit from Object.prototype and therefore may not have a hasOwnProperty() method (and indeed in IE < 9, they generally do not).
  • A simple Boolean coercion (e.g. if (object.property) { ... }) is a poor test of the existence of a property, since it will give false negatives for falsy values. For example, for an empty textarea, if (textarea.selectionStart) { ... } will not execute the block even though the property exists. Also, some host object properties throw an error in older versions of IE when attempting to coerce to a Boolean (e.g. var xhr = new ActiveXObject("Microsoft.XMLHTTP"); if (xhr.responseXML) { ... }).
  • The in operator is a better test of the existence of a property, but there are once again no guarantees about support for it in host objects.
  • I recommend against considering performance for this kind of task. Choose the safest option for your project and only optimize later. There will almost certainly be much better candidates for optimization than property existence checks.

For more background on this, I recommend this excellent article by Peter Michaux.

Tim Down
  • 318,141
  • 75
  • 454
  • 536
  • 1
    Are you sure the `in` operator is not necessarily available for host objects? After all, it is an operator that works on objects. And I thought all objects in javascript, including host objects, are still fundamentally sets of property/value pairs, so the in operator should apply, right? – Ben Lee Aug 24 '11 at 17:00
  • @Ben Lee: I'm not sure if it ever throws an error, but it's not completely reliable for host objects. It doesn't work for detecting event handler properties in Firefox, for example: `"onmouseover" in document` returns `false`. Support actually seems better than I remember, judging by a bit of googling: the best I can find is a mention from kangax in the comments to the following: http://www.nczonline.net/blog/2010/07/27/determining-if-an-object-property-exists/ – Tim Down Aug 24 '11 at 17:17
  • 2
    @Ben Lee: Also, looking at section 8.6.2 of the ECMAScript 3 spec (which is still the baseline for the set of browsers in general use today), it specifically states that a host object may choose to implement or not whichever internal methods it likes, including `[[HasProperty]]` (which is what the `in` operator relies on). So in short, it seems the spec is saying that there are no guarantees. – Tim Down Aug 24 '11 at 17:29
2

Definitely if ('property' in object) is the right way to go. That actually tests if the property is in the object (or in its prototype chain, more on that below).

if (object.property) on the other hand, will coerce 'property' into a truth/flase value. If the property is unset, it will return "undefined", which will be coerced into false, and appear to work. But this will also fail for a number of other set values of properties. javascript is notoriously inconsistent in what it treats as truthy and falsy.

Finally, like I said above, 'property' in 'object' will return true if it's in anywhere in the prototype chain. If you want to test that's on the object itself, and not somewhere higher up in the chain, you use the hasOwnProperty method like so:

if (object.hasOwnProperty('property')) ...
Ben Lee
  • 52,489
  • 13
  • 125
  • 145
0

The first one would fail if "property" is false of 0. To make sure that there actually exist a property you need to check that object.property !== undefined, or use the in-keyword.

[Edit]

There is also the hasOwnProperty-function, but I've never really used that one so I can't say much about it. Though I think it won't return true if the property is set in a prototype, which sometimes you want, other times you don't want.

Alxandr
  • 12,345
  • 10
  • 59
  • 95
  • 3
    A property can exist and be undefined. (And if you want to test for undefinedness, then `typeof object.property === "undefined"` is safer). – Quentin Aug 24 '11 at 11:37
  • Isn't setting a property to undefined the same as deleting it? Or does it still show up if you iterate over properties? – Alxandr Aug 24 '11 at 11:38
  • 1
    @Alexandr, no it's not the same. try `a = {}; a.x = undefined; a.hasOwnPropety('x') == true; a.hasOwnProperty('y') == false;` – Ben Lee Aug 24 '11 at 11:44
  • 1
    To remove a property, you do `delete object.property` – Ben Lee Aug 24 '11 at 11:45
  • Huh. Didn't know. That is the part about setting a property to undefined actually setting the property. I knew about the delete keyword though. Just thought they did the same. – Alxandr Aug 24 '11 at 11:45
0

This allows you to use window.hasOwnProperty as either referring to itself or something else, regardless of your scripting host.

// No enclosing functions here
if (!('hasOwnProperty' in this))
    function hasOwnProperty(obj, prop) {
        var method = Object.prototype.hasOwnProperty;
        if (prop === undefined)
            return method.call(this, obj);
        return method.call(obj, prop);
    }

//Example of use
var global = global || this; //environment-agnostic way to get the global object
var x = 'blah';
WScript.Echo(global.hasOwnProperty('x') ? 'true' : 'false'); //true

//Use as non-object method
var y = { z: false };
WScript.Echo(hasOwnProperty(y, 'z') ? 'true' : 'false'); //true
WScript.Echo(hasOwnProperty(y, 'w') ? 'true' : 'false'); //false

// true ಠ_ಠ
WScript.Echo(hasOwnProperty(global, 'hasOwnProperty') ? 'true' : 'false');
Fordi
  • 2,798
  • 25
  • 20