Javascript's hasOwnProperty() Method Is More Consistent Than The IN Operator

Posted May 11, 2010 at 9:22 AM by Ben Nadel

Tags: Javascript / DHTML

This is just a very quick follow-up to my previous post on using Javascript's IN operator with String values. When I first blogged a while back about using Javascript's IN operator, James Padolsey had mentioned to me that the hasOwnProperty() method was basically doing the same thing that the IN operator was doing. After finding out that Javascript's IN operator failed to work with String objects, I figured I'd see if I had any better luck with this hasOwnProperty() method. I took the previous demo code and reworked it to use this new method:

  • <!DOCTYPE HTML>
  • <html>
  • <head>
  • <title>Javascript hasOwnProperty() Method And String Objects</title>
  • <script type="text/javascript">
  •  
  • // Create a number of different data types to test.
  • var stringValue = "";
  • var objectValue = {};
  • var arrayValue = [];
  • var dateValue = new Date();
  • var numberValue = new Number( 1 );
  • var boolValue = true;
  •  
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  •  
  • // Run control group known to work.
  • console.log( "Object", objectValue.hasOwnProperty( "length" ) );
  •  
  • // Run test on array.
  • console.log( "Array", arrayValue.hasOwnProperty( "length" ) );
  •  
  • // Run test on date object.
  • console.log( "Date", dateValue.hasOwnProperty( "length" ) );
  •  
  • // Run test on number object.
  • console.log( "Number", numberValue.hasOwnProperty( "length" ) );
  •  
  • // Run test on boolean object.
  • console.log( "Boolean", boolValue.hasOwnProperty( "length" ) );
  •  
  • // Try to use the IN operator on a String value.
  • console.log( "String", stringValue.hasOwnProperty( "length" ) );
  •  
  • </script>
  • </head>
  • <body>
  • <!-- Intentionally left blank. -->
  • </body>
  • </html>

As you can see, I'm simply using the hasOwnProperty() method in lieu of the IN operator. When we run this code, we get the following console output:

Object false
Array true
Date false
Number false
Boolean false
String true

As you can see, the hasOwnProperty() method works perfectly with all the tested data types (even the String and the Boolean value which was not previously demonstrated).

The hasOwnProperty() method is doing, more or less, what the IN operator is doing with one major exception - the IN operator inspects the object's prototype chain while the hasOwnProperty() method does not. As such, the hasOwnProperty() method will return false even if an object has the given inherited property. Essentially, the hasOwnProperty() method checks to see if an object has the given key defined locally and not whether it has access to such a key at all.

Personally, I'd like to see the IN operator work with all of Javascript's core data types; but since it doesn't, the hasOwnProperty() method can work in place of it to some degree. And, of course, as Ben Alman pointed out, you can always use the typeof() function to check the type of objects you are dealing with before making use of the IN operator.




Reader Comments

May 11, 2010 at 12:44 PM // reply »
69 Comments

In my experience, a "for (... in ...)" loop on a string iterates over the characters of the string.


May 11, 2010 at 9:05 PM // reply »
53 Comments

Papa Crockford recommends combining the two for looping through object properties. 'in' is used to enumerate the properties and hasOwnProperty ensures the property is a method of your object and not part of the chain ie.

function each( object, callback, args ){
var prop;
for( prop in object ){
if( object.hasOwnProperty( i ) ){
callback.apply( prop, args );
}
}
}

http://javascript.crockford.com/code.html#for statement

jQuery uses object[prop] to check those values. string["length"] worked, so maybe this is a viable shortcut to the longer name?
http://github.com/jquery/jquery/blob/master/src/core.js line 542


May 11, 2010 at 9:06 PM // reply »
53 Comments

Sorry broken link:
http://javascript.crockford.com/code.html#for%20statement


May 16, 2010 at 10:02 PM // reply »
10,640 Comments

@Drew,

He says that it should be used as a "defensive" move to make sure an object truly has a given property; but, I am not sure I fully understand that concept. If objects are going to inherit from each other, it seems counter-productive to try and check around the inheritance chain.

I'm not a OO master, though, so I am probably just not seeing something.


May 16, 2010 at 10:18 PM // reply »
53 Comments

That is a good point, I bet that is probably why jQuery uses the object["property"] technique. This would include inherited properties.


Aug 30, 2010 at 4:48 PM // reply »
1 Comments

@Ben: the point is to let you reliably use Objects as dictionaries/maps/hashes by making sure that no extra keys show up besides the ones you put into a given instance.

This is mostly a problem when you're using a third-party library that monkeypatches Object.prototype. If it adds its new .niftyMethod(), then if you do this:

var obj = { "a": 1, "b":, 2, "c": 3}
for (var k in obj) {
v = obj[k];
...
}

The body of your loop will be executed four times, not three; the extra iteration will have k set to "niftyMethod" and v set to that method's closure body.


Sep 5, 2010 at 1:21 PM // reply »
10,640 Comments

@Mark,

I understand what you're saying; but, I am having trouble thinking of times when I would need to worry about that kind of object-definition "security". I'm relatively new to the world of OO, so I am sure there is good theory behind this.


Aug 31, 2011 at 10:33 AM // reply »
2 Comments

What I have found is that hasOwnProperty is excellent in most cases but if you use a javascript class library such as John Resig's or JavascriptMVC's and you want to callback a method laying inside the parent class you'll need to use the IN keyword because as you have explained prototype inheritance isn't supported in hasOwnProperty.

for instance:

Class.extends('parent', {

methodWithCallback: function(obj, args, callback) {

...

//Will Not Work
if(obj.hasOwnProperty(callback)) {
self[callback](obj);
}

//Will Work
if(callback in obj) {
self[callback](obj);
}

...

},

callbackName: function(obj)

});

class.extends('child', {

withCallback: function() {

try {

var self = this;

this.methodWithCallback(self, args, "callbackName");

} catch(e) {}

}

});

At least I couldn't make it work but I've only been working with JavascriptMVC for a few days now.


Aug 31, 2011 at 10:39 AM // reply »
53 Comments

True, hasOwnProperty() is used to distinguish actual properties of an object from those in the prototype. https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/hasOwnProperty

in is a pretty horrible way to find properties, because it requires the browser to find ALL properties of an object up the entire chanin, then look for the property you are asking it. This is quite slow, but may be useful if you don't know the name of the property you are looking for.


Aug 31, 2011 at 1:42 PM // reply »
2 Comments

@Drew

You are right of course. The problem is that when you try to make js work like a conventional class-based inheritance language you have to use its slower constructs. What I do is do a typeof == string to see if I don't know the name (ie I need to look at the object members ) then look to the child class's methods first for a callback with hasOwnProperty and failing that I look for the member using IN.

I store the callback names in my object inside a member object. It will either store a string for unknowns I wan to pass in as an argument or I pass in a function to that callback object when I set an input to a jquery reference.

so if typeof callback == "string" it will do its dirty dance through the properties then execute the callback.

if it is typeof callback == "function" it will just execute the function.

The latter is the preferred method but I like giving the framework entry options. This way anything that needs to be appliaction wide can go in the parent and anything localized to my child can go there. And if something is quick and dirty it can just be put in the init() call when I set inputs and callbacks for said input.


Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
InVision App - Prototyping Made Beautiful With Prototyping Tools Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
Feb 8, 2012 at 11:09 AM
Building A Fixed-Position Bottom Menu Bar (ala FaceBook)
Here's a warning about using fixed top or bottom menu bars that hasn't been mentioned. Browsers don't factor fixed bars into the page height for page up and page down, meaning you'll have anything f ... read »
Feb 8, 2012 at 10:32 AM
Building A Twitter-Inspired RESTful API Architecture In ColdFusion
@Andy, Ah, very cool. FW/1 really seems to be quite well-rounded these days! ... read »
Feb 8, 2012 at 9:52 AM
Building A Twitter-Inspired RESTful API Architecture In ColdFusion
Just wanted to let you know that version 2.0 of Sean Corfield's FW/1 supports routing. This allows you to build true RESTful APIs using ColdFusion. (search for "URL Routes" https://github ... read »
Feb 8, 2012 at 2:05 AM
Creating A Fixed-Length Queue In JavaScript Using Arrays
Cool site ... read »
Feb 7, 2012 at 5:00 PM
Ask Ben: Ending ColdFusion Session When User Closes Browser
We've used code that sets the cookies without the "expires" attribute in most of our applications to accommodate an "automatic logoff" (Let's face it, that's what we're really try ... read »
Feb 7, 2012 at 10:10 AM
Ask Ben: Building An AJAX, jQuery, And ColdFusion Powered Application
Hey Ben great post. Just like @Carl Steinhilber I am having the same trouble with the -'parseerror'. But I can only reach GET contacts-demo.cfm I have added secureJSON="no" ... read »
ang
Feb 7, 2012 at 4:46 AM
Using The Apple iPod Shuffle Without iTunes
i got the same error with munkey!! help please!! ... read »
Feb 7, 2012 at 2:48 AM
Ask Ben: Javascript String Replace Method
@Kadut, . is a special character you will need to escape it \. ... read »