views:

43

answers:

2

Basically everyone writing about member enumeration in JavaScript heavily advocates the use of the hasOwnProperty method as to avoid going up the prototype-chain.

I understand that this is a form of defensive programming as to prevent iterating over members that are added, for example, to the Object.prototype. But what about the other inherited members? Say, members that are very close in the prototype chain...members that you actually Want to be enumerated over.

Let's say I have the following:

var beget = function (o) { // http://javascript.crockford.com/prototypal.html
    function F() {};
    F.prototype = o;
    return new F();
};

var john = { name: 'john', surname: 'grech' },
    mary = beget(john),
    p;

mary.age = 42; //augmenting 'mary'

// 'surname' in mary              => true
// mary.hasOwnProperty('surname') => false

for (p in mary) {
    //skipping over non-direct members, meaning that we also skip members
    //inherited from 'john'
    if (!mary.hasOwnProperty(p)) { 
        continue;
    }
    console.log(p);
}

In the above sample, only age will be displayed, since age is the only direct-member of mary...the other two members, name and surname, are up the prototype chain.

But obviously, I want all the 3 members to be iterated over in the for..in construct; but if you remove the hasOwnProperty, you can then get members from Object.Prototype if someone adds functions to it.


So this is my dilemma.

Do you use prototypal inheritance in combination with the hasOwnProperty method but risk getting members that are too far up the chain during enumeration?

Or do you use the other forms of inheritance that add members directly to the object rather than the prototype?

A: 

If you need to iterate over the prototypal chain of an object you can use hasOwnProperty to skip direct members (as you said). This will of course also iterate through whichever other member that was added to the prototype of that object (Object.Prototype etc..). There's no way to avoid this.

It's like asking how to avoid enumerating over certain members of a car = {yellow, green, black} object (pseudocode)... you don't... you simply skip certain members based on their value.


Adding members directly to an object isn't really a form of inheritance, unless of course you create objects using the begetObject() technique... because it uses the Prototype to add members.

Luca Matteis
I did not say that augmenting an object by adding direct members is inheritance. But using the the `beget` function, you are making use of prototypal inheritance since the members of the class you are 'inheriting' from are added to the propotype.
Andreas Grech
With that said, your answer does not bring me any closer to understanding what should be done.
Andreas Grech
@Andreas: It's not really clear what you're trying to do. If you're trying to iterate over an object, I answered your question. If you're trying to do inheritance using direct members and begetObject(), what is your question?
Luca Matteis
+1  A: 

Hm. You are saying " very close in the prototype chain", but actually, what does it mean very close? Is the three level deep "close" or "far".

Anyway, you could change a bit beget function and implement own hasOwnProperty function for every object, which would go through the prototype chain only till the Object level. This will solve your dilemma of getting members which are added to the Object.prototype by not using hasOwnProperty. Code attached bellow:

var beget = function (o) { // http://javascript.crockford.com/prototypal.html
    function F() {
        this.hasOwnProperty = function(key) {
            return (key != "hasOwnProperty" 
                && Object.prototype.hasOwnProperty.call( this, key ) 
                || o.hasOwnProperty( key )
            );
        }
    };

    F.prototype = o;
    return new F();
};

var john = { name: 'john', surname: 'grech' },
    mary = beget( john ),
    p    = beget( mary );

mary.age  = 42; //augmenting 'mary'
mary.name = "mary";
p.size    = "38";

// testing prototype of Object.
Object.prototype.not_own = function(){}

for(var i in p) {
    console.debug('Key',i, p.hasOwnProperty(i));
}

// p.hasOwnProperty("size");    // -> true
// p.hasOwnProperty("age");     // -> true
// p.hasOwnProperty("name");    // -> true
// p.hasOwnProperty("not_own"); // -> false
nemisj