Death to hasOwnProperty: not only is it annoying to type, but nowadays it is rarely appropriate.

posted 2012-Mar-21

Summary

Using hasOwnProperty by default when iterating over keys of an object used to be the Right Thing To Do. I argue that it is no longer correct, now that we can control the enumerability of custom-added properties.

Details

Iterating through an object’s keys and values in JavaScript is relatively easy (if not as terse as I might like):

var people = {
  doug : { age:38, male:true,  kg:80 },
  jane : { age:34, male:false, kg:65 }
};
for (var name in people){
  var data = people[name];
  // Use name and data
}

The above code is what a lot of novice JavaScript developers would write. (They also unwisely use for…in to iterate arrays, but that’s another issue.) Then some jerk would come along and add a method or property to Object.prototype and suddenly their code would break, because all properties of the object are included, even inherited ones.

A lot of scripters are under the impression that it’s never OK to extend Object.prototype, or Array.prototype, or any other built-in prototype, and for most of them it’s because of the above problem. I do not share this opinion. It’s hogwash.

From time immemorial (or at least 1996, which is about as far back as I can remember, anyhow) the wise JavaScripter would instead iterate over an object’s properties like so:

for (var name in people){
  if (!people.hasOwnProperty(name)) continue;
  var data = people[name];
  // Use name and data, securely knowing that they are not inherited
}

Yes, it added a lot of salt to the wound of verbosity. And yes, the performance impact is too much for some speed-critical applications. But it was the Right thing to do, and I ~always wrote defensive code using it. But no more, I say!

In July of 2010 JavaScript 1.8.5 introduced Object.defineProperty (and other related convenience methods). In addition to allowing you to define getter and setter methods that look like properties, this gem also allows you to define a property that is not enumerated. For example, instead of this 8-year old code I can now write:

Object.defineProperty(Object.prototype,'toSourceCode',{
  enumerable:false,  // this is the default value, but let's be very clear
  value:function(){
    
  }
});

…and voila! I have a method that can be invoked on any object but that does not appear in the for…in iterations. So if I can trust myself to never make a property enumerable that I don’t want to enumerate, I never have to write a hasOwnProperty test again. Moreover, if I can now trust the intent of a property’s enumerability, I mostly shouldn’t use hasOwnProperty; if someone makes an intentionally-enumerable property that is inherited by my object, I likely should be including that property in my iteration.

Yes, IE8 had a broken half-assed implementation of defineProperty, and this browser is still quite present in the wild Internet. (Globally it appears that roughly 15% of visitors are using it in March of 2012.) However, the problem is detectable, shims exist that fix this problem, and ‘presently’ this browser will be all-but-unused.

Next time you go to write hasOwnProperty(), save your wrists some typing and stop to think: “Is this really the right thing to do?”

thecodeparadox
01:25PM ET
2012-Apr-19

Awesome informations. thanks. I designed a function alternative to hasOwnProperty(), check Check Javascript Object has a Property and please gimme suggestion if have

Me
03:46AM ET
2014-Jan-14

“Then some jerk..”

Why is he a jerk? He can’t be an oracle for every line of code in a project!

lilag
09:05PM ET
2014-Feb-11

“So if I can trust myself to never make a property enumerable that I don’t want to enumerate, I never have to write a hasOwnProperty test again.”

Naive man! :) 3rd-party libraries can bring you surprises.

askelkana
09:55AM ET
2014-Jul-07

But as long as you’re having to support IE8, you cannot rely on having Object.defineProperty, so this isn’t dead an buried by any means.

paladin
09:57AM ET
2014-Oct-08

good post, though possibly it was a little soon at time of writing. true that certian 3rd party code may possibly add to the inherited prototypes, but only as long as we give those libraries the crutch to do so.

here in late 2014, ie8 is more and more a legacy browser and, as developers, we have the responsibility to push the ie10 minimum now that it’s got auto-updating baked in.

net.mind details other résumé contact
Phrogz.net