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 Object.create() 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.
Disclaimer: Any viewpoints and opinions expressed in this article are those of Nicholas C. Zakas and do not, in any way, reflect those of my employer, my colleagues, Wrox Publishing, O'Reilly Publishing, or anyone else. I speak only for myself, not for them.
Both comments and pings are currently closed.




19 Comments
Hey Nicholas,
I think it’s worth to note that if the hasOwnProperty method is overwritten, you can rely on the Object.prototype.hasOwnProperty.call(object, property).
Great post btw
Pablo Cabrera on July 27th, 2010 at 9:27 am
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.hasOwnProperty.call(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?)
kangax on July 27th, 2010 at 10:11 am
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.
Peter van der Zee on July 27th, 2010 at 1:50 pm
What about: typeof obj.prop != “undefined” ?
Kyle Simpson on July 27th, 2010 at 2:35 pm
@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…
Alexander on July 27th, 2010 at 3:34 pm
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.
Dmitry A. Soshnikov on July 27th, 2010 at 4:18 pm
@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.Nicholas C. Zakas on July 27th, 2010 at 9:58 pm
@Nicholas: in the sentence you listed NaN and false as truthy values
John Peloquin on July 28th, 2010 at 12:37 am
Think you added “NaN, false” in the wrong place.
Zach Leatherman on July 28th, 2010 at 10:10 am
> 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.
Dmitry A. Soshnikov on July 28th, 2010 at 4:06 pm
@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
Jesse D Pate on July 29th, 2010 at 4:24 pm
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
Kyle Simpson on August 3rd, 2010 at 2:22 pm
Very interesting on the performance side of this discussion:
http://jsperf.com/undefined/2
Kyle Simpson on August 4th, 2010 at 5:14 pm
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.
Kyle Simpson on August 7th, 2010 at 12:18 pm
@Kyle – just a small nitpick, there is actually a property named “undefined” on the
windowobject. You can try it for yourself viawindow.hasOwnProperty("undefined").Nicholas C. Zakas on August 7th, 2010 at 10:34 pm
cause
//doesn’t accurately test for existence
if (person.name){
//yay! property exists!
}
person.name could exists as a false value
Ramon Lechuga on August 10th, 2010 at 1:40 pm
there is also a method called isPrototypeOf which checks if one object’s prototype exists in another object.
adamlu on August 11th, 2010 at 2:22 am
[...] Determining if an object property exists (nczonline.net) [...]
Prototypal Inheritance in JavaScript « Rupesh kumar Tiwari on September 15th, 2010 at 5:14 pm
[...] un par de dÃas leà este interesante artÃculo acerca de la comprobación de la existencia de una propiedad en un objeto de [...]
Propiedades de Objetos, ¿Cómo comprobarlas? editablething on October 6th, 2010 at 1:39 pm
Comments are automatically closed after 14 days.