Determining if an object property exists

One of the most basic tests developers perform in JavaScript is whether or not a particular property exists on an object. Since feature detection is the preferred method of code forking, developers are encouraged to test for the existence of properties before using them. There is a lot of buggy JavaScript code out there as inexperienced developers try to use feature detection. A lot of the problems reside with a lack of understanding as to the nature of object properties in JavaScript.

Where do properties come from?

Before attempting to detect properties, it’s important to understand from where they originate. There are two basic types of properties in JavaScript: those that exist on the object (also known as “own” properties) and those that are inherited through the prototype chain (often called “prototype” properties). Consider the following:

var person = {
    name: "Nicholas"
};

alert(person.name);        //"Nicholas"
alert(person.toString());  //"[object Object]"

In this code, the object person has only one own property, which is name. You can still access other methods on the object such as toString(), but these are inherited through the prototype chain. Object literals inherit from the Object type, so all of the basic methods of Object are accessible on the instance.

The big difference between own properties and prototype properties is the difference between unique and shared values. Own properties belong to that single object instance and can’t be affected by other instances of the same type; prototype properties belong to the prototype of the object, and since the prototype can be shared amongst multiple instances, these properties are also shared amongst multiple instances. Here’s another example:

var person2 = Object.create(person);
var person3 = Object.create(person);

alert(person2.name);   //"Nicholas"
alert(person3.name);   //"Nicholas"

person.name = "Adam";

alert(person2.name);    //"Adam"
alert(person3.name);    //"Adam"

This example uses the <a href="http://javascript.crockford.com/prototypal.html">Object.create()</a> method from ECMAScript 5 to create two objects, person2 and person3, that inherit from person. The prototype for both person2 and person3 is person, and so name is actually a prototype property that is accessible through person2 and person3. This is why displaying the values of name on both objects results in the same value: they are both sharing the prototype property name. That means when person.name is changed directly, the change is accessible from the instances.

It’s important to understand that name is a prototype property for both person2 and person3, but it’s an own property for person. You can only assign values to own properties, so attempting to assign a value to a prototype property actually causes a new own property of the same name to be created. Example:

alert(person2.name);    //"Nicholas"
alert(person3.name);    //"Nicholas"

person2.name = "Adam";

alert(person2.name);    //"Adam"
alert(person3.name);    //"Nicholas"

Since you can’t assign to prototype properties, assigning a new value to person2.name actually creates a new own property on person2 called name. Own properties always shadow prototype properties, so the next time you access person2.name, you’re accessing the own property instead of the prototype property. That will continue until the own property is removed using delete, such as:

delete person2.name;

alert(person2.name);    //"Nicholas"

You can only call delete on an own property to remove it (calling on a prototype property does nothing). Once the own property name is removed, there is nothing shadowing the prototype property name and so person2.name now refers to the prototype property.

Note: While all native object types (Array, Boolean, Date, all Error variants, Function, Number, RegExp, and String) inherit from Object, non-native object types, such as those that represent the DOM in browsers, don’t necessarily inherit from Object in all browsers.

Detecting properties

Let’s say you want to determine if a given object has a property of name. In experienced developers tend to write code like this:

//doesn't accurately test for existence
if (person.name){
    //yay! property exists!
}

At first glance, this seems okay. However, understanding how JavaScript works reveals some problems with this approach. First, this will only succeed if the value of person.name is truthy, meaning it’s an object, a non-empty string, a non-zero number that’s not NaN, true, and not null or undefined. That means if person.name is the empty string (“”), this check will fail. Failing, in this case, doesn’t mean that the property doesn’t exist. In fact, the property does exist and contains a value, but the value is falsy and so doesn’t pass this test.

Detecting own properties

Keeping in mind that this is about testing for the existence of the property and not for the usability or data type, there are a couple of options. The first option is to detect own properties, and it comes via a method on the Object type called hasOwnProperty(). Since native objects inherit from Object, this property is inherited by these objects and can be used to detect the existence of own properties:

alert(person.hasOwnProperty("name"));   //true
alert(person2.hasOwnProperty("name"));    //false

person2.name = "Adam";

alert(person2.hasOwnProperty("name"));    //true

delete person2.name;

alert(person2.hasOwnProperty("name"));    //false

Initially, person2 has a prototype property name, so hasOwnProperty() returns false. Once an own property is created, calling hasOwnProperty() returns true. And after the property is removed via delete, this method again returns false.

JSON serialization works only for own properties, and non-native JSON serialization utilities used hasOwnProperty() to ensure that only the properties defined on object literals were included in the resulting string.

Detecting all properties

If you only care that the object has a property and don’t care whether it’s an own property or a prototype property, you can use the in operator to determine the existence of the property. Example:

if ("name" in person){
    //property exists
}

The in operator returns true when the named property exists on the object. In many cases, the in operator is all that you’ll need (especially when dealing with DOM objects). In fact, Mark Pilgrim’s All-In-One Almost-Alphabetical No-Bullshit Guide to Detecting Everything for HTML5 makes extensive use of in for detecting the new HTML5 features on DOM objects.

Conclusion

If you just want to check for the existence of properties, and not necessarily what their value might be, then you have two safe options: hasOwnProperty() and the in operator. The hasOwnProperty() property method should be used if you want to detect own properties only. If you want to test property existence and don’t care if it’s an own property or an object property, then the in operator is the one to use.

Update (27 July 2010): Added false and NaN to list of falsy values.****

Update (29 July 2010): Fixed description of truthy/falsy values.

Update (22 December 2012): Fixed link to Mark Pilgrim’s list.

Comments

  1. Pablo Cabrera

    Hey Nicholas,

    I think it's worth to note that if the hasOwnProperty method is overwritten, you can rely on the Object.prototype.hasOwnProp...(object, property).

    Great post btw

  2. kangax

    There are a couple more important considerations to be aware of:

    1) Calling `hasOwnProperty` off the object itself is not as safe as it seems — property might be perfectly legally _shadowed_ by a user-defined one with the same name but different value. An object can also be orphaned from `Object.prototype` (i.e. have `null` in its [[Prototype]]) — e.g. when created via ES5-allowed `Object.create(null, ...)`. This is solved by calling `hasOwnProperty` off `Object.prototype` itself: `if (Object.prototype.hasOwnProp...(object, property)) { ... }` (or `({}).hasOwnProperty.call(object, property)` as a slower alternative).

    2) `hasOwnProperty` can produce unexpected results in certain implementations. In Mozilla, for example, `({}).hasOwnProperty('__proto__')` reports `true` even though object looks like it's empty (e.g. if it was just created).

    3) When it comes to host objects, `in` operator lies as well (unsurprising to anyone familiar with wonderfully sporadic nature of host objects). For example, alert(["0" in document.forms[0],document.forms[0][0]]); alerts "false,[object HTMLInputElement]" in Mozilla (this finding is courtesy of Garrett Smith). The usual rule to never trust host objects is relevant with `in` just as with any other operator.

    4) Finally, older Safari (some versions of 2.x) do not implement `hasOwnProperty` and crash when applying `in` on certain host objects (nodelists, IIRC). Just something to be aware of...

    (minor nitpick: did you miss `false` and `NaN` from non-truthy values?)

  3. Peter van der Zee

    Although the warning about host objects is fair, they (should) indeed only apply to host objects. And when it comes to host objects, almost anything goes (even though the spec does put up a few restrictions, certain implementations have a lengthy record of failing to follow them).

    I think it's important we start focussing on what ecmascript (js) does, not what browsers do with host objects. Especially with the rise of SSJS (server side js like node.js). Host objects are generally evil and anything you can do with them is only because "they" let you.

  4. Kyle Simpson

    What about: typeof obj.prop != "undefined" ?

  5. Alexander

    @Kyle,

    Indeed, we've used the typeof notation on most sites that I've worked on. BUT - I don't remember if we settled on that because it was more robust than other property detection methods or what...

    You can also drop the typeof operator and the quotes around 'undefined' as 'undefined' is an actual datatype in JS, e.g. if(obj.prop !== undefined){ }

    But if('prop' in obj){ } is quite a bit smaller and seems like it would be readily understandable for new devs working on an existing code base...

  6. Dmitry A. Soshnikov

    Good overview.

    @Nicolas

    > Since you can’t assign to prototype properties

    Don't forget about accessor properties (since you mention ES5 and Object.create from it) -- it's easy to assign to inherited property.

    @Kyle Simpson

    > What about: typeof obj.prop != “undefined” ?

    It just checks for the result of typeof operator, not existing a property in general.

    obj.prop = undefined;

    typeof obj.prop != “undefined” // false

    Dmitry.

  7. Nicholas C. Zakas

    @kangax - Thanks, I've added the other falsy values. I have a lousy tech editor (me). I thought that it was Safari 1.x, though, that was missing hasOwnProperty() and that 2.x added it back in?

    @Pablo/kangax - Great suggestions for calling Object.prototype.hasOwnProperty.call().

    @Dmitry - That's a good point about accessor properties. I assume you're thinking that you can define a setter for a property and the setter assigns the value to the prototype's property of the same name?

    @Kyle - I agree with Dmitry's answer. You're testing for a value of undefined, not whether the property exists in the object or not. One of the weird (wonderful?) parts of JavaScript: typeof window.undefined. :)

  8. John Peloquin

    @Nicholas: in the sentence you listed NaN and false as truthy values :)

  9. Zach Leatherman

    Think you added "NaN, false" in the wrong place.

  10. Dmitry A. Soshnikov

    > the setter assigns the value to the prototype’s property of the same name

    Yes, assignment doesn't always mean creating/updating of the own property:

    var _x = 10;

    var proto = {
    get x() {
    return _x;
    },
    set x(x) {
    _x = x;
    }
    };

    print(proto.hasOwnProperty("x")); // true

    print(proto.x); // 10

    proto.x = 20; // set own property

    print(proto.x); // 20

    var a = Object.create(proto); // "a" inherits from "proto"

    print(a.x); // 20, read inherited

    a.x = 30; // set *inherited*, but not own

    print(a.x); // 30
    print(proto.x); // 30
    print(a.hasOwnProperty("x")); //false

    However, if "a" would have own property, assignment will set own one:

    var a = Object.create(proto, {
    x: {
    value: 100,
    writable: true
    }
    });

    print(a.x); // 100, read own

    a.x = 30; // set also own

    print(a.x); // 30
    print(proto.x); // 20
    print(a.hasOwnProperty("x")); // true

    The same result can be obtained and via setting own property using meta-method, but not assignment operator:

    var a = Object.create(proto);

    a.x = 30; // set inherited

    Object.defineProperty(a, "x", {
    value: 100,
    writable: true
    });

    a.x = 30; // set own

    Dmitry.

  11. Jesse D Pate

    @Kyle --

    typeof if how I've generally checked for things, but instead of just checking that they aren't undefined, I have always checked against expected data type. E.G.

    typeof obj.prop == 'object'

    or

    !isNaN(Number(obj.prop))

    or something along those lines. Of course, doing this can lead throw some errors if you're skipping down a level.

    var obj = {};
    typeof obj.foo.oops; // Whoops

  12. Kyle Simpson

    I completely disagree on the point that since "undefined" is a datatype in JavaScript, you can just use a magical keyword `undefined` and be fine.

    In fact, there is no such `undefined` keyword, nor is there an automatic global variable of that name. You're just taking advantage of the fact that if you reference a variable which has never been declared, a reference to it returns the underlying default "undefined" (aka, "NotAValue") value. And your morphing the data type's value into a variable name of the same word, which references a variable that is no more special than "foo" except that rarely do people assign valid values to a variable they call "undefined". But sometimes they do, either on purpose or accidentally.

    var obj = {prop:"foo"}, undefined=2;
    if (obj.prop2 == undefined) { // false!
    obj.prop2 = "bar";
    }

    the `typeof` operator on the other hand returns a definitive (and immutable, therefore reliable) string value that is always "undefined" when dealing with variables/properties that are either undeclared, uninitialized or have otherwise been unset using delete or void 0 or something.

    alert(window.foo == window.undefined); // true
    alert(window.foo === window.undefined); // true
    var undefined = true;
    alert(window.foo == window.undefined); // false!

    But:

    alert(typeof window.foo == "undefined"); // always true if foo is truly undeclared/uninitialized/unset

  13. Kyle Simpson

    Very interesting on the performance side of this discussion:

    http://jsperf.com/undefined/2

  14. Kyle Simpson

    One last important thing to note:

    It appears from my testing that only "hasOwnProperty" checks can distinguish between an object property that was deleted using the "delete" operator versus an object property being "unset" by setting it to an undefined value (like void 0, for instance). "hasOwnProperty" correctly returns false on deleted properties from an object or indexes from an array, whereas it appears the other techniques don't propertly detect that case.

  15. Nicholas C. Zakas

    @Kyle - just a small nitpick, there is actually a property named "undefined" on the window object. You can try it for yourself via window.hasOwnProperty("undefined").

  16. Ramon Lechuga

    cause
    //doesn't accurately test for existence
    if (person.name){
    //yay! property exists!
    }

    person.name could exists as a false value :P

  17. adamlu

    there is also a method called isPrototypeOf which checks if one object's prototype exists in another object.

Understanding JavaScript Promises E-book Cover

Demystify JavaScript promises with the e-book that explains not just concepts, but also real-world uses of promises.

Download the Free E-book!

The community edition of Understanding JavaScript Promises is a free download that arrives in minutes.