for..in, hasOwnProperty(), and inheritance

Axel Rauschmayer axel at rauschma.de
Tue Nov 8 10:37:11 PST 2011


What’s the use case?

Don’t forget that whenever you set a property, you only ever modify the first object in the prototype chain.

The “own property” debate mainly exists, because objects are (ab)used as dictionaries. Then you don’t want inherited entries such as "toString".


On Nov 8, 2011, at 8:59 , Felipe Gasper wrote:

> Hi everyone,
> 
> 	There is a widespread practice of doing this:
> 
> ---------
> for (key in obj) {
>    if (obj.hasOwnProperty(key)) { … }
> }
> ---------
> 
> The oft-stated purpose for this pattern is to weed out code that comes from Object.prototype. The result, though, is that we prevent iteration through *any* inherited properties, which seems like overkill for handling the original problem.
> 
> (Incidentally, I’m surprised that augmenting Object.prototype isn’t warned/deprecated in ES5 Strict. It seems far easier to get people to stop augmenting Obj.pro, which is likely to break all kinds of things, than to get everyone to filter every for..in loop. But, anyway.)
> 
> It’s especially unproductive because it works against prototypal inheritance patterns. e.g.:
> ---------
> var dog = { speak: function() { return "arf!" } };
> var beagle = Object.create(dog);
> beagle.colors = ["white","black","brown"];
> var my_dog = Object.create(beagle);
> my_dog.name = "Chip";
> ---------
> Note that filtering via hasOwnProperty() will prevent a for..in iteration from seeing either "colors" or "speak".
> 
> Another example: in YUI, it’s impossible to do this would-otherwise-be-useful pattern:
> ---------
> var base_config = { width: "600px" };
>> var my_config = Object.create(base_config);
> my_config.visible = false;
> var widget = new Y.Widget(my_config);
> ---------
> In the example above, YUI will not see the “width” property because YUI rejects all inherited properties when it iterates through the configuration hash.
> 
> 
> 
> So, a solution I am considering for my own work defines two methods:
> Object.gave(giver, key, obj)
> Function.prototype.gave(key,obj)
> 
> They do what they look like: Object.gave checks if the “giver” really “gave” the “key”ed value to the “obj”ect. The Function.prototype version does the same but assigns the function’s prototype as “giver”. (The original Object.gave() offloads to the prototype method if called with just two args.)
> 
> Thus:
> ------------------
> var HOP = Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);
> Object.gave = function(giver,key,obj) {
>    if (arguments.length === 2) {
>        Function.prototype.gave.apply(this,arguments);
>    }
> 
>    var last_prototype;
>    while ( obj !== giver ) {
>        if (HOP(obj,key) || (obj === last_prototype)) return false;
>        last_prototype = obj;
>        obj = Object.getPrototypeOf(obj);
>    }
> 
>    return true;
> };
> 
> Function.prototype.gave = function(key,obj) {
>    return Object.gave( this.prototype, key, obj );
> };
> ------------------
> 
> Then, we can do:
> --------------
> for (var key in obj) {
>    if (Object.gave(key,obj)) { … }
> }
> --------------
> 
> …which will still filter out anything in Object.prototype, but will allow iteration through inherited properties.
> 
> This seems to me far more useful in general than the hasOwnProperty() check.
> 
> Thoughts?
> 
> -Felipe Gasper
> cPanel, Inc.
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss

-- 
Dr. Axel Rauschmayer
axel at rauschma.de

home: rauschma.de
twitter: twitter.com/rauschma
blog: 2ality.com



-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20111108/ad344470/attachment-0001.html>


More information about the es-discuss mailing list