Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Robust hasOwnProperty

6 views
Skip to first unread message

raider5

unread,
Aug 31, 2010, 6:23:36 PM8/31/10
to
I recently tried out "My Library" (looks nice), and noticed it doesn't
use hasOwnProperty, instead is uses a custom isOwnProperty function.
I've written an alternative hasOwnProperty function to handle a couple
of edge cases isOwnProperty doesn't:


var hasOwnProperty = (function(hop){
return hop ? function(o,p){
return hop.call(o,p);
}:function(o,p){
var proto = o.constructor.prototype, b = true, t;

if(p in proto){
t = proto[p];
b = (proto[p]=1) !== o[p] || (proto[p]=2) !== o[p];
proto[p] = t;
}

return b;
};
}(Object.prototype.hasOwnProperty));

function testIsOwnProperty(){
this.a=1;
}
testIsOwnProperty.prototype.a=1;
testIsOwnProperty.prototype.b=undefined;

var o = new testIsOwnProperty();

for(var p in o){
if(hasOwnProperty(o,p)){
alert(p+':'+o[p]); //a:1
}
}


I'm curious as to what others have implemented for hasOwnProperty
should it not exist? And if there is an alternative method that is
preferable?

RobG

unread,
Aug 31, 2010, 9:44:33 PM8/31/10
to
On Sep 1, 8:23 am, raider5 <raid...@hotmail.co.uk> wrote:
> I recently tried out "My Library" (looks nice), and noticed it doesn't
> use hasOwnProperty, instead is uses a custom isOwnProperty function.
> I've written an alternative hasOwnProperty function to handle a couple
> of edge cases isOwnProperty doesn't:

Which are?


> var hasOwnProperty = (function(hop){
> return hop ? function(o,p){
> return hop.call(o,p);
> }:function(o,p){
> var proto = o.constructor.prototype, b = true, t;
>
> if(p in proto){
> t = proto[p];
> b = (proto[p]=1) !== o[p] || (proto[p]=2) !== o[p];
> proto[p] = t;
> }
>
> return b;
> };
>
> }(Object.prototype.hasOwnProperty));
>
> function testIsOwnProperty(){
> this.a=1;}
>
> testIsOwnProperty.prototype.a=1;
> testIsOwnProperty.prototype.b=undefined;
>
> var o = new testIsOwnProperty();
>
> for(var p in o){
> if(hasOwnProperty(o,p)){
> alert(p+':'+o[p]); //a:1
> }
> }
>
> I'm curious as to what others have implemented for hasOwnProperty
> should it not exist? And if there is an alternative method that is
> preferable?

It's usually possible to remove the need for hasOwnProperty. It only
seems useful to me when copying properties from one object to another
using a for..in statement and there is a requirement to filter out
inherited enumerable properties. In those cases it can be specified
that only objects created using Object as a constructor or an object
literal should be passed as arguments (and of course that
Object.prototype isn't modified).

A related issue is where properties added to an object have the same
name as non-enumerable properties of Object.prototype (such as
toString and valueOf) and they are ignored by for..in (as happens in
IE). One strategy is something like:

if (obj.toString != Object.prototype.toString) {

/* obj has a toString property that isn't inherited
* from Object.prototype.toString, deal with it
*/
}

Of course that doesn't work if obj.toString is inherited from some
other prototype, such as when working across frames, in more complex
inheritance schemes or if obj is a function or some other type of
object. Perhaps hasOwnProperty can be used here? It would require
testing the list of possible properties that might fail, there is no
way of knowing the full extent of such a list, it can only be
discovered by trial and error and it would make the for..in loop
slower.

To me, if it can't be made bullet-proof, a general solution is doomed.
Better to document the exceptions as they are discovered and either
design away the need or work within known safe limits.


--
Rob

Garrett Smith

unread,
Aug 31, 2010, 9:56:41 PM8/31/10
to
On 2010-08-31 06:44 PM, RobG wrote:
> On Sep 1, 8:23 am, raider5<raid...@hotmail.co.uk> wrote:
>> I recently tried out "My Library" (looks nice), and noticed it doesn't
>> use hasOwnProperty, instead is uses a custom isOwnProperty function.
>> I've written an alternative hasOwnProperty function to handle a couple
>> of edge cases isOwnProperty doesn't:
>
That method is missing from older webkits and using it on global object,
indirectly, has surprising results in Opera.

Where `__proto__` is available it can be used to make a better guess and
I think kangax had a way to determine with certainty using a more
elaborate trick that involved deleting the object's `__proto__`
property, performing a test with `in`, and then restoring `__proto__`.
That required feature tests to determine if `__proto__` was deletable
and then restorable.

[...]


> To me, if it can't be made bullet-proof, a general solution is doomed.
> Better to document the exceptions as they are discovered and either
> design away the need or work within known safe limits.
>
>

A strategy which I've gotten away with (so far) is to limit the need for
`hasOwnProperty` and then put my own wrapped `hasOwnProperty` function
inside a closure, for use within that closure only.
--
Garrett

Asen Bozhilov

unread,
Sep 1, 2010, 8:22:24 AM9/1/10
to
raider5 wrote:


> var hasOwnProperty = (function(hop){
>     return hop ? function(o,p){
>         return hop.call(o,p);
>     }:function(o,p){
>         var proto = o.constructor.prototype, b = true, t;
>
>         if(p in proto){
>             t = proto[p];
>             b = (proto[p]=1) !== o[p] || (proto[p]=2) !== o[p];
>             proto[p] = t;

Don't touch my prototypes :) You cannot be sure that property is
exactly at this point of prototype chain. What will be happen if I
have prototype chain like follow:

Foo.prototype:
x : 10
^
Bar.prototype:

var instance = new Bar();
instance.x; //10

hasOwnProperty(instance, 'x'); //false

Foo.prototype.x = 50;
instance.x; //10 Expected result here is 50

So please, do not shadow properties in prototype chain. Your approach
itself needs built-in `hasOwnProperty' :)


>         }
>
>         return b;
>     };
>
> }(Object.prototype.hasOwnProperty));
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
What is the main goal of this?

Asen Bozhilov

unread,
Sep 1, 2010, 8:28:38 AM9/1/10
to
Garrett Smith wrote:

> Where `__proto__` is available it can be used to make a better guess and
> I think kangax had a way to determine with certainty using a more
> elaborate trick that involved deleting the object's `__proto__`
> property, performing a test with `in`, and then restoring `__proto__`.
> That required feature tests to determine if `__proto__` was deletable
> and then restorable.

We have discussed that topic. If the `__proto__' is writeable and it's
mimic of internal [[Prototype]] you don't need feature test for
deletable and restorable. You can do:

var obj = {},
proto = obj.__proto__;

//Truncate prototype chain
obj.__proto__ = {__proto__ : null};

//Restore the old state of prototype chain
obj.__proto__ = proto;

raider5

unread,
Sep 1, 2010, 10:45:28 AM9/1/10
to
> > I recently tried out "My Library" (looks nice), and noticed it doesn't
> > use hasOwnProperty, instead is uses a custom isOwnProperty function.
> > I've written an alternative hasOwnProperty function to handle a couple
> > of edge cases isOwnProperty doesn't:
>
> Which are?

If the object and prototype contain a property with the same name and
value it returns false (expected true). If there is a property on the
prototype with an undefined value and no property on the object with
the same name, it returns true (expected false).


> A related issue is where properties added to an object have the same
> name as non-enumerable properties of Object.prototype (such as
> toString and valueOf) and they are ignored by for..in (as happens in
> IE). One strategy is something like:
>
>   if (obj.toString != Object.prototype.toString) {
>
>     /* obj has a toString property that isn't inherited
>      * from Object.prototype.toString, deal with it
>      */
>   }

Yeah that is the first part of the problem, iterating through the
object. I have checks in place for this already, something along the
line of:

var hasDontEnumBug = true;
for(var p in {toString:1}){
hasDontEnumBug = false;
}

If the bug is present manually loop through the non-enumerable
properties:
['toString', 'valueOf', 'toLocaleString', 'hasOwnProperty',
'isPrototypeOf', 'propertyIsEnumerable', 'constructor']


raider5

unread,
Sep 1, 2010, 10:48:54 AM9/1/10
to
> Where `__proto__` is available it can be used to make a better guess and
> I think kangax had a way to determine with certainty using a more
> elaborate trick that involved deleting the object's `__proto__`
> property, performing a test with `in`, and then restoring `__proto__`.
> That required feature tests to determine if `__proto__` was deletable
> and then restorable.

I'll check this out.


> A strategy which I've gotten away with (so far) is to limit the need for
> `hasOwnProperty` and then put my own wrapped `hasOwnProperty` function
> inside a closure, for use within that closure only.

Do you have an example I could take a look at?


Asen Bozhilov

unread,
Sep 1, 2010, 10:54:45 AM9/1/10
to
raider5 wrote:

> Yeah that is the first part of the problem, iterating through the
> object. I have checks in place for this already, something along the
> line of:
>
> var hasDontEnumBug = true;
> for(var p in {toString:1}){
>     hasDontEnumBug = false;
>
> }

No, this is wrong assumption. If `hasDontEnumBug = false' that mean
object has one or more enumerable properties. With code like this you
cannot be sure that `toString' property has been enumerated. For
example:

Object.prototype.breakHasDontEnumBug = true;

Now try your detection of DontEnum bug.

Better use:

var hasDontEnumBug = !{toString :
true}.propertyIsEnumerable('toString');

raider5

unread,
Sep 1, 2010, 10:54:21 AM9/1/10
to
> > var hasOwnProperty = (function(hop){
> >     return hop ? function(o,p){
> >         return hop.call(o,p);
> >     }:function(o,p){
> >         var proto = o.constructor.prototype, b = true, t;
>
> >         if(p in proto){
> >             t = proto[p];
> >             b = (proto[p]=1) !== o[p] || (proto[p]=2) !== o[p];
> >             proto[p] = t;
>
> Don't touch my prototypes :) You cannot be sure that property is
> exactly at this point of prototype chain. What will be happen if I
> have prototype chain like follow:
>
> Foo.prototype:
>     x : 10
>      ^
> Bar.prototype:
>
> var instance = new Bar();
> instance.x; //10
>
> hasOwnProperty(instance, 'x'); //false
>
> Foo.prototype.x = 50;
> instance.x; //10 Expected result here is 50
>
> So please, do not shadow properties in prototype chain. Your approach
> itself needs built-in `hasOwnProperty' :)

I'm a bit confused by what you mean, if the following is what you are
referring to then it seems ok to me, am I missing something?

function Foo(){}
Foo.prototype.x = 10;

function Bar(){}
Bar.prototype = Foo.prototype;

var instance = new Bar();

hasOwnProperty(instance,'x'); //false < the correct result as Bar
doesn't have its own 'x'

Foo.prototype.x = 50;
instance.x; // 50 as expected


> > }(Object.prototype.hasOwnProperty));
>
>     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> What is the main goal of this?

An additional precaution in case the current object has an overridden
hasOwnProperty property.

Asen Bozhilov

unread,
Sep 1, 2010, 10:57:54 AM9/1/10
to
raider5 wrote:

> I'm a bit confused by what you mean, if the following is what you are
> referring to then it seems ok to me, am I missing something?
>
> function Foo(){}
> Foo.prototype.x = 10;
>
> function Bar(){}
> Bar.prototype = Foo.prototype;
>
> var instance = new Bar();
> hasOwnProperty(instance,'x'); //false < the correct result as Bar
> doesn't have its own 'x'
>
> Foo.prototype.x = 50;
> instance.x; // 50 as expected

No.

function Foo(){}
Foo.prototype.x = 10;

function Bar(){}
Bar.prototype = new Foo();
Bar.prototype.constructor = Bar;

var instance = new Bar();

Test now ;)

raider5

unread,
Sep 1, 2010, 11:16:14 AM9/1/10
to
> function Foo(){}
> Foo.prototype.x = 10;
>
> function Bar(){}
> Bar.prototype = new Foo();
> Bar.prototype.constructor = Bar;
>
> var instance = new Bar();
>
> Test now ;)

I'm still not clear on what the test is. Neither of the constructors
have their own properties and the results are as expected, what am I
missing?

function Foo(){}
Foo.prototype.x = 10;

function Bar(){}
Bar.prototype = new Foo();
Bar.prototype.constructor = Bar;

var instance = new Bar();

alert(hasOwnProperty(instance,'x')); //false < the correct result as


Bar doesn't have its own 'x'
Foo.prototype.x = 50;

alert(instance.x); // 50 as expected

Asen Bozhilov

unread,
Sep 1, 2010, 1:17:26 PM9/1/10
to
raider5 wrote:

> I'm still not clear on what the test is. Neither of the constructors
> have their own properties and the results are as expected, what am I
> missing?

You have tested with built-in `hasOwnProperty'.

var hasOwnProperty = (function(hop){
return function(o,p){


var proto = o.constructor.prototype, b = true, t;

if(p in proto){
t = proto[p];
b = (proto[p]=1) !== o[p] || (proto[p]=2) !== o[p];
proto[p] = t;
}

return b;
};
}(Object.prototype.hasOwnProperty));


function Foo(){}
Foo.prototype.x = 10;

function Bar(){}
Bar.prototype = new Foo();
Bar.prototype.constructor = Bar;

var instance = new Bar();

print(hasOwnProperty(instance, 'x')); //false
Foo.prototype.x = 50;
print(instance.x); //10

Asen Bozhilov

unread,
Sep 1, 2010, 1:29:37 PM9/1/10
to
Asen Bozhilov wrote:
> raider5 wrote:
> > I'm still not clear on what the test is. Neither of the constructors
> > have their own properties and the results are as expected, what am I
> > missing?
>
> You have tested with built-in `hasOwnProperty'.

And there is another problem with you `hasOwnProperty' implementation.
If property does not exist in the prototype chain your function
returns `true'.
Try it the follow code:

hasOwnProperty({}, 'foo'); //true

It must returns `false'.

Ry Nohryb

unread,
Sep 1, 2010, 7:12:48 PM9/1/10
to
On Sep 1, 12:23 am, raider5 <raid...@hotmail.co.uk> wrote:
> (...)

> I'm curious as to what others have implemented for hasOwnProperty
> should it not exist? And if there is an alternative method that is
> preferable?

//create a test object
a= {}
//save its prototype
saved= a.__proto__;
//cut the prototype chain
a.__proto__= null;
//test with 'in': it now behaves as a .hasOwnProperty.
"toString" in a
--> false
a.toString= 27
"toString" in a
--> true
//Restore the prototype chain
a.__proto__= savedProto;

The problems: most browsers in which this runs have .hasOwnProperty()
already, and I'd bet this -too- fails in IEs (what doesn't?), and
"__proto__" in a is always going to return true.

What do you need this for ?
--
Jorge.

David Mark

unread,
Sep 2, 2010, 1:01:42 AM9/2/10
to
On Sep 1, 10:45 am, raider5 <raid...@hotmail.co.uk> wrote:
> > > I recently tried out "My Library" (looks nice), and noticed it doesn't
> > > use hasOwnProperty, instead is uses a custom isOwnProperty function.
> > > I've written an alternative hasOwnProperty function to handle a couple
> > > of edge cases isOwnProperty doesn't:
>
> > Which are?
>
> If the object and prototype contain a property with the same name and
> value it returns false (expected true). If there is a property on the
> prototype with an undefined value and no property on the object with
> the same name, it returns true (expected false).
>

Just so everyone is on the same page, isOwnProperty was never meant to
be a hasOwnProperty equivalent (hence the different, but perhaps too-
close name).

As documented, it is only intended to be used as a for-in filter (to
skip Object.prototype augmentations added by evil scripts).

0 new messages