for in Intrigue

By YUI TeamSeptember 26th, 2006

One 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.

33 Comments

  1. typeof obj[name] !== ‘function’

    You mean:

    typeof obj[name] != ‘function’

    (one to many equal signs).

  2. 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.

  3. @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..in iteration 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.

  4. Michal Tatarynowicz said:
    September 26, 2006 at 3:32 pm

    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);

  5. [...] for in Intrigue » Yahoo! User Interface Blog (tags: javascript) [...]

  6. 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?

  7. 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.

  8. 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, '');
    }

  9. Your trim() example has lost all of its backslashes.

  10. hi there,

    can you make YUI blog have a printer friendly link for nice offline reading ?

    thank you,

    BR,
    ~A

  11. 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.

  12. 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.

  13. @anjan: Good suggestion, I’ll add it to our feature request list.

    Thanks,
    Nate

  14. [...] 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 ) [...]

  15. Here is a fix I believe should fix the hasOwnProperty:

    /* Safari

  16. Matt Sweeney said:
    October 5, 2006 at 1:35 pm

    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.

  17. @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.

  18. I have never seen the !! operator before – what does it do?

  19. !! converts a truthy value to true, and a value to false. It is similar to the Boolean() function.

  20. 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…

  21. Brent Robientt said:
    July 5, 2007 at 11:27 am

    It seems like like the biggest problem with augmenting Object.prototype with new properties is that you pretty much never want include those properties when iterating over an object. So why not test against Object.prototype directly?:

    for (name in obj) {
    if (Object.prototype[name] === undefined) {
    ...
    }
    }

  22. 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);

  23. François B. said:
    July 12, 2007 at 5:49 am

    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

  24. 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, propertyIsEnumerable is specified such that coforming implementations will have the exact same result as with hasOwnProperty.

    Method propertyIsEnumerable does not check the prototype chain (15.2.4.7). Since all programmer-defined properties are enumerable. Therefore, propertyIsEnumerable provides the behavior that Doug so desires.

    The fact that propertyIsEnumerable does 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 propertyIsEnumerable does not check the prototype chain is, in fact, a bug that

    Unfortunately, JScript suffers from another bug that causes propertyIsEnumerable to return false on a user-defined object property.

    This happens when the value that is passed to propertyIsEnumerable exists 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.

  25. correction:
    For programmer-defined objects, propertyIsEnumerable is specified such that coforming implementations will have the exact same result as with hasOwnProperty.

    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 ))

  26. @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'
    }

  27. 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…

  28. 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.

  29. 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!

  30. 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,'');
    }
    }

  31. 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.

  32. @Paul

    That’s the style I’d use, ever since I learned it from Wil Shipley’s blog (Delicious Monster) for reducing nesting and improving readability, as you said. Essentially, set up conditionals to bail out immediately if the there’s nothing to do because of the circumstances not being met. Great suggestion, IMHO.