for..in, hasOwnProperty(), and inheritance

Jake Verbaten raynos2 at gmail.com
Tue Nov 8 10:29:48 PST 2011


Whats wrong with enumeration over own properties?

Object.keys() gets all enumerable own properties in a for .. in loop.

for .. in gets all enumerable properties in prototype chains.

I personally think it's bad practice to have code that enumerates over
properties in the prototype chain. I can't see any good use case for it

On Tue, Nov 8, 2011 at 7:59 AM, Felipe Gasper <felipe at felipegasper.com>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<https://mail.mozilla.org/listinfo/es-discuss>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20111108/df62eea4/attachment.html>


More information about the es-discuss mailing list