for in Intrigue
September 26, 2006 at 9:21 am by Douglas Crockford | In Development | 32 CommentsOne of JavaScript’s best features is the ability to augment the built-in types. If we want to add a new method to a type, we simply assign a function to the type’s prototype. So, if I think that JavaScript strings should have a trim method (and they should) then I can write
String.prototype.trim = function () {
return this.replace( /^\\s*(\\S*(\\s+\\S+)*)\\s*$/, "$1");
}
Now all of my strings have a trim method, even strings that were constructed before I did the augmentation.
We can do this for any of the built-in types: Object, Array, Function, Number, String, and Boolean. This is a source of great expressive power which can help JavaScript realize its potential as dynamic, functional, object-oriented language.
JavaScript is, sadly, also a flawed language, and one of its flaws interacts badly with augmentation of Object. But fortunately, we can mitigate the problem.
The flaw is that the for in statement, which can enumerate the keys stored in an object, produces all of the keys in the object’s prototype chain, not just the keys in the object itself. This causes inherited methods to appear in the enumeration, which is bad. If would have been nicer if JavaScript did not contain this flaw, but fortunately we can program around it.
In all of the A Grade browsers, we should always write for in statements in this form:
for (name in obj) {
if (obj.hasOwnProperty(name)) {
...
}
}
It is deeply annoying that we have to include the extra if statement to filter out the extraneous values. It would seem better to ignore the flaw and code in ignorance. This is possible if you can guarantee that your code will never interact with programs that will augment Object.prototype. But as we get better at mashups and code sharing, ignorance produces brittleness. The standard describes an augmentable Object.prototype. Ignore standards at your own peril.
The hasOwnProperty method is useful in making JavaScript’s objects act as general containers. For example, suppose you are keeping a list of key words where each word is used as a key. We can quickly determine if a word is in our list:
function check_word(word) {
return !!words[word];
}
Unfortunately, the function can produce the wrong result if the word is "constructor" because there will be a constructor property in words’s prototype chain. We can use hasOwnProperty to filter out the chain.
function check_word(word) {
return words.hasOwnProperty(word);
}
One of the unfortunate consequences of the language having gone through multiple versions is that not every JavaScript environment provides the hasOwnProperty method. IE 5.0 and Safari 1.3 do not. If your program has to run in those as well, then there is an older equivalent that is almost as good, in which we filter out function values.
for (name in obj) {
if (typeof obj[name] !== 'function') {
...
}
}
function check_word(word) {
return typeof words[word] !== 'function';
}
Would it be better if JavaScript were not flawed? Absolutely. But it is flawed, and you can only get so far by pretending that it isn’t.
Share and extend: Bookmark with Yahoo! My Web | Bookmark with del.icio.us | digg it! | reddit!
32 Comments »
RSS feed for comments on this post. TrackBack URI
Leave a comment

Copyright © 2006-2010 Yahoo! Inc. All rights reserved. Privacy Policy - Terms of Service
Powered by WordPress on Yahoo! Web Hosting.

typeof obj[name] !== ‘function’
You mean:
typeof obj[name] != ‘function’
(one to many equal signs).
Comment by Peter Foti — September 26, 2006 #
Breaking “for in” loops is just one thing. Another is that you break the “in” operator in general. And the strongest argument for using no extensions at all is the compatibilitys between different libraries. It may be possible that someone has another implementation idea of an extension.
Comment by Sebastian Werner — September 26, 2006 #
@Peter: Either will work. The !== operator checks for strict equivalence (matching types), while the != operator checks for lax equivalence. “0 != false” returns false, but “0 !== false” returns true.
Of course, since typeof will always return a string, the two operators are interchangeable in this context.
@Douglas: Well-written as always. I echo the sentiment that defensive
for..initeration should become the norm. As you may know, Dean Edwards wrote about this a while back, describing an excellent method for avoiding collisions with object prototypes.Comment by Andrew Dupont — September 26, 2006 #
Ehm, hello, am I missing something?
if (!Object.prototype.hasOwnProperty){
Object.prototype.hasOwnProperty = function(p){
return typeof this[p] != ‘function’;
}
}
Object.prototype.each = function(fn){
for (var p in this) {
if (!this.hasOwnProperty(p)) fn(this[p]);
}
}
var foo = new Object;
var callback = function(a){ alert(a); }
foo.each(callback);
Comment by Michal Tatarynowicz — September 26, 2006 #
[...] for in Intrigue » Yahoo! User Interface Blog (tags: javascript) [...]
Pingback by BarelyBlogging » Blog Archive » links for 2006-09-27 — September 26, 2006 #
Maybe better:
Object.prototype.hasOwnProperty = function (prop) {
return this[prop] !== this.prototype[prop];
}
Though I suppose this might mean that obj.hasOwnProperty(’something_that_does_not_exist’) is true?
Comment by Ian Bicking — September 26, 2006 #
I think this description sort of cheapens the power of the
hasOwnProperty()method. It’s job isn’t to determine if a key contains a function or not, it’s job is to determine if the key was added directly to this object instance or if it was added through the prototype chain. You may very well want to add a function under a key, in which case testing for a function doesn’t help out very much.Comment by Nicholas C. Zakas — September 26, 2006 #
This may be a nit and totally not the point of the post, but I think there’s an easier regex for trimming:
String.prototype.trim = function () {
return this.replace(/^\s+|\s+$/g, '');
}
Comment by Matthew Frank — September 27, 2006 #
Your trim() example has lost all of its backslashes.
Comment by Johan Sunsdtröm — September 27, 2006 #
hi there,
can you make YUI blog have a printer friendly link for nice offline reading ?
thank you,
BR,
~A
Comment by anjan bacchu — September 27, 2006 #
Douglas, why do you consider for…in’s behavior to be a flaw? I know I’ve come up on situations where I’m very interested in knowing all the keys on an object, especially the inherited ones.
Comment by Jeff Stewart — September 28, 2006 #
typeof is also flawed (besides the fact that I would prefer to use instanceof) since this is perfectly valid:
Array.prototype.foo = ‘bar’;
Personally I would prefer something like this:
if (!Object.prototype.hasOwnProperty)
{
Object.prototype.hasOwnProperty = function(p)
{
return this.constructor.prototype[p] === undefined;
}
}
And personally I don’t find the for-in behavior a flaw; I think there are good reasons to enumerate inherited properties as well.
Comment by Tino Zijdel — September 28, 2006 #
@anjan: Good suggestion, I’ll add it to our feature request list.
Thanks,
Nate
Comment by Nate Koechley — September 28, 2006 #
[...] for in Intrigue » Yahoo! User Interface Blog Douglas Crockford discusses using JavaScript and prototype properties…. also check out the comment re: !== and !=. Who knew? (categories: javascript prototype programming ) [...]
Pingback by Aaron Johnson » Blog Archive » Links: 9-30-2006 — October 1, 2006 #
Here is a fix I believe should fix the hasOwnProperty:
/* Safari
Comment by Kris Zyp — October 5, 2006 #
I prefer using “propertyIsEnumerable” for this. It seems more appropriate than “hasOwnProperty” for the task of enumeration, and is more widely supported across browsers.
Also, for folks considering augmenting built-in types, keep in mind that this pollutes the global namespace, and should be used with EXTREME caution, if ever.
Comment by Matt Sweeney — October 5, 2006 #
@Matthew – your RegExp works well, too. I think a lot of people adopted the prior one because your RegExp would actually fail in Netscape 4.x (I know, who uses that browser any more?). I know I used one similar to Crockford’s for a long time just out of habit.
Comment by Nicholas C. Zakas — October 6, 2006 #
I have never seen the !! operator before – what does it do?
Comment by Bill — October 6, 2006 #
!! converts a truthy value to true, and a value to false. It is similar to the Boolean() function.
Comment by Douglas Crockford — October 6, 2006 #
JavaScript is not flawed with for-in loop just because this loops grabs all enumerable properties all along the inheritance chain: there can be situations where it is perfectly needed.
JavaScript is flawed because we cannot manage isPropertyEnumerable flag, but only read it. That would be a years long dream of mine to be able to do something like:
obj.someProperty = someValue;
obj.someProperty.isEnumerable = false;
Besides solving the for-in loop problem, it would be also a “cheap-chat” protected members emulation: not a bulletproof (as in any run-time compiled language) but very easy to use:
obj.secretName = someFunction;
obj.secretName.isEnumerable = false;
Dreams, dreams…
Comment by VK — October 16, 2006 #
It seems like like the biggest problem with augmenting
Object.prototypewith new properties is that you pretty much never want include those properties when iterating over an object. So why not test againstObject.prototypedirectly?:for (name in obj) {
if (Object.prototype[name] === undefined) {
...
}
}
Comment by Brent Robientt — July 5, 2007 #
There is are two remote yet possible bugs in doing exactly as the article recommends. The first happens when the particular object whose properties one is enumerating has a custom property ‘hasOwnProperty’, and the second happens when Object.prototype is assigned a custom ‘hasOwnProperty’. There is a workaround for the first bug.
for(var key in obj) {
if(Object.prototype.hasOwnProperty.call(obj, key)) {
...
}
}
or, more compactly,
for(var key in obj) {
if({ }.hasOwnProperty.call(obj, key)) {
...
}
}
This would be familiar if you’ve seen code like
var myargs = [ ].slice.call(arguments, 2);
myfunc.apply(myobj, myargs);
Comment by Jay — July 11, 2007 #
Hi Douglas !
Very interesting list of articles here.
But I found a bug in your last code snippet that makes the function return true for undefined variables !
var words = {'foo' : 'foo',
'bar' : 'bar'
}
function check_word(word) {
return typeof words[word] !== 'function';
}
alert(check_word('foo')); // true
alert(check_word('foobar')); // true !!! it should be false
So here is a quick correction :
function check_word(word) {return typeof words[word] !== 'undefined' &&
typeof words[word] !== 'function';
}
alert(check_word('foo')); // true
alert(check_word('foobar')); // false ! it's ok now
Comment by François B. — July 12, 2007 #
Checking the object by using typeof can in no way be considered a replacement for
hasOwnProperty. It is quite likely that a functional value exists in the iterated object’s instance (a method).Using “in” will check the prototype chain.
This feature can be useful for examining the prototype chain. For example, if you wanted to generically advise each method in a Panel
class, you could iterate through all the functions in the object’s prototype chain.
If you think about it, it can be a useful feature.
In fact, the “flaw” that Doug mentions is intentional behavior of the language. As mentioned in earlier comments, it is a perfectly valid feature (read above).
Sweeney mentioned using propertyIsEnumerable to check an object’s properties in lieu of missing hasOwnProperty.
Interestingly,
propertyIsEnumerableis specified such that coforming implementations will have the exact same result as withhasOwnProperty.Method
propertyIsEnumerabledoes not check the prototype chain (15.2.4.7). Since all programmer-defined properties are enumerable. Therefore,propertyIsEnumerableprovides the behavior that Doug so desires.The fact that
propertyIsEnumerabledoes not check the prototype chain is itself a bug of the spec. David Flanagan pointed this out and Brendan will readily admit that it’s a bug. JScript and SpiderMonkey both implement the spec correctly in this aspect.The fact that
propertyIsEnumerabledoes not check the prototype chain is, in fact, a bug thatUnfortunately, JScript suffers from another bug that causes
propertyIsEnumerableto return false on a user-defined object property.This happens when the value that is passed to
propertyIsEnumerableexists in the instance and overrides a non-enumerable (DontEnum) property in the object’s prototype chain (such as an overridden “toString”)Matthew Frank provides a tighter version of trim, and there’s nothing wrong with adding
trim, however, it should be done conditionally:if(!String.prototype.trim)String.prototype.trim = function () {
return this.replace(/^\s+|\s+$/g, '');
};
The conditional check is necessary because future versions of ECMAScript will have
String.prototype.trim.@Andrew Dupont the
!==will produce the same result as!=when both operands are string values (returns false if the sequence of characters is not an exact match,). I would probably opt for!=though.Comment by Garrett — September 9, 2007 #
correction:
For programmer-defined objects,
propertyIsEnumerableis specified such that coforming implementations will have the exact same result as withhasOwnProperty.var obj = {Garrett : "monkeybrains"
,borked : "javascript" // transitivity fixed :-)
,toString : function() { return "an enumerable prop"; }
,valueOf : function() { return 2; } // also enumerable.
};
// can this be false for any value of s?
(obj.hasOwnProperty( s ) != obj.propertyIsEnumerable( s ))
Comment by Garrett — September 11, 2007 #
[...] More related info about hasOwnProperty. [...]
Pingback by GUYA.NET » Blog Archive » Resolving some issues with swfobject — November 11, 2007 #
@Douglas: I know this article is 5 months old, but since it is being linked by JSLint, you should really fix that last code sample so that it doesn’t return true for undefined keys.
function check_word(word) {
return typeof words[word] !== 'function'
&& typeof words[word] !== 'undefined'
}
Comment by henrah — April 4, 2008 #
First an editorial, then some science.
It’s just wrong to say that a js Object is not a prop/value hash, should not be used as such, and then go on to implement an alternate hash mechanism. Objects certainly are hashes (dictionaries, key/value pairs), but they don’t behave exactly like hashes in some other languages. Yes, because of prototyping and inheritance a js hash can get additional members. Using hasOwnProperty is a correct way to filter these – that is, it’s a correct way to use an object hash in javascript. Do you really want to write a custom hash object just to avoid the one-line property check? Like so many libraries and toolkits out there, this smacks as an effort to turn javascript into a different language. These efforts usually result in overhead, obfuscation and maintenance challenges.
Ok, the science. I wanted to know the overhead of adding a hasOwnProperty() check. I also timed the alternate (inferior) “typeof obj[key] !== ‘function’” check. Instead of over-burdening this comment with the full results, if you’re interested, the engine is at http://randomous.com/tools/misc/timer.php. The results of timing tests relevant to this article are at the bottom of that page.
Cheers…
Comment by byron — June 11, 2008 #
Looks to me like additional shallow versions of the in operator and the for in loop statement (which do not follow the prototype chain) would be a useful extension of the language.
Comment by Stefan — July 4, 2008 #
Is this too ugly?
for_own(objects, function (o) {
// ...
});
Where for_own would be something like:
function for_own(obj, fun) {
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
fun(key);
}
}
};
Greets!
Comment by Emmanuel Oga — October 6, 2008 #
for those who are interested, i’m using the following to allow for more php-style trim() (where specific characters/strings can be trimmed from the string):
if (!String.prototype.trim) {
String.prototype.trim = function (chars) {
var that = this.toString();
chars = chars || '\\s';
if (Array.isArray(chars)) {
chars = chars.join('|');
}
var re = new RegExp('^(' + chars + ')+|(' + chars + ')+$','g');
return that.replace(re,'');
}
}
Comment by Stephen — October 7, 2008 #
When processing for (p in o) loops, is there anything wrong with the continue statement? I prefer to do the following:
for (p in o) {
if (!o.hasOwnProperty(p)) {
continue;
};
// more code
}
I find that this helps to reduce nesting and makes for more readable code.
Comment by Paul Dunbar — October 14, 2009 #