Non standard __proto__ and null value in SpiderMonkey

A

Asen Bozhilov

__proto__ property in some implementation of ECMA-262 is mimic of
internal [[Prototype]] property. More information can be found on:
<URL: https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Object/proto
/>

In SpiderMonkey implementation every native object has own property
`__proto__`, which refer next object in prototype chain.

var obj = {};

window.alert(obj.__proto__ === Object.prototype); //true

The next object in prototype chain of object referred by `obj' is
Object.prototype. The prototype chain of that object looks:

obj -> Object.prototype -> null

window.alert(obj.hasOwnProperty('__proto__')); //true
window.alert(obj.propertyIsEnumerable('__proto__')); //false

`__proto__' is own property of that object and has internal attribute
{DontEnum}, which mean that property cannot be enumerate during `for-
in` loop.

window.alert(delete obj.__proto__); //false

Even {DontEnum} attribute that property has and {DontDelete} internal
attribute.

But if I assign primitive null value on that property in SpiderMonkey
some of the described things above are changed.

var obj = {__proto__ : null};
window.alert(Object.prototype.propertyIsEnumerable.call(obj,
'__proto__')); //false
window.alert(delete obj.__proto__); //true

`__proto__' still have {DontEnum} attribute but do not have
{DontDelete} yet. That is not the big problem. The problem is
`__proto__' yet is not mimic of internal [[Prototype]]. The previous
state of prototype chain cannot be restored.

var obj = {};
obj.__proto__ = null;
obj.__proto__ = Object.prototype;

window.alert(Object.prototype.isPrototypeOf(obj)); //false

I use `obj.__proto__ = null;` to create short prototype chain and when
I want to do some things over own properties of that object. For
example, enumerate only own properties, without examine whole
prototype chain for properties which are not have {DontEnum}
attribute. And of course that save me of calling `hasOwnProperty` on
each iteration.

I use workaround with intermediate object in prototype chain.

var obj = {},
proto = obj.__proto__;
obj.__proto__ = {__proto__ : null};
// Do something with own properties
obj.__proto__ = proto; // Restore previous state of prototype chain

Is this behavior is a bug in SpiderMonkey? I do not found any
information about that. Perhaps the readers of c.l.js can explain why
they implement that in this way.

Thanks for responses.
 
T

Thomas 'PointedEars' Lahn

Asen said:
I use `obj.__proto__ = null;` to create short prototype chain

Without that assignment the prototype chain of the Object instances
referred to by `obj' is

Object.prototype

Trying to shorten that is overkill.
and when I want to do some things over own properties of that object.
For example, enumerate only own properties, without examine whole
prototype chain for properties which are not have {DontEnum}
attribute. And of course that save me of calling `hasOwnProperty` on
each iteration.

Do not augment Object.prototype, or use Arrays, and you will not have that
problem.
I use workaround with intermediate object in prototype chain.

var obj = {},
proto = obj.__proto__;
obj.__proto__ = {__proto__ : null};
// Do something with own properties
obj.__proto__ = proto; // Restore previous state of prototype chain

Is this behavior is a bug in SpiderMonkey?

It is a known issue.
I do not found any information about that.

It has been discussed here before.
Perhaps the readers of c.l.js can explain why they implement that in
this way.

Probably an oversight in the setter.


PointedEars
 
A

Asen Bozhilov

Thomas said:
Without that assignment the prototype chain of the Object instances
referred to by `obj' is

  Object.prototype

Trying to shorten that is overkill.

Regarding used example, you are correct. I use that example, because
it was easy to concentrate on `__proto__' and the things in my
previous post. I will never use that approach for object, which has
prototype chain:

obj -> Object.prototype -> null

or

arr -> Array.prototype -> Object.prototype -> null

It can be used, when the prototype chain is long and there are objects
created by developer. For example If you want `copy' method, which
produce *shallow* copy of the object, how can you implement that? With
*shallow* I mean, should be copied only own properties of that
object.
Do not augment Object.prototype, or use Arrays, and you will not have that
problem.

It was discussed many time here and I totally agree with your
attentions and I never augment built-in prototypes.
 
D

Dmitry A. Soshnikov

__proto__ property in some implementation of ECMA-262 is mimic of
internal [[Prototype]] property.  More information can be found on:
<URL:https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global...>

In SpiderMonkey implementation every native object has own property
`__proto__`, which refer next object in prototype chain.

var obj = {};

window.alert(obj.__proto__ === Object.prototype); //true

The next object in prototype chain of object referred by `obj' is
Object.prototype. The prototype chain of that object looks:

obj -> Object.prototype -> null

window.alert(obj.hasOwnProperty('__proto__')); //true
window.alert(obj.propertyIsEnumerable('__proto__')); //false

`__proto__' is own property of that object and has internal attribute
{DontEnum}, which mean that property cannot be enumerate during `for-
in` loop.

window.alert(delete obj.__proto__); //false

Even {DontEnum} attribute that property has and {DontDelete} internal
attribute.

But if I assign primitive null value on that property in SpiderMonkey
some of the described things above are changed.

var obj = {__proto__ : null};
window.alert(Object.prototype.propertyIsEnumerable.call(obj,
'__proto__')); //false
window.alert(delete obj.__proto__); //true

`__proto__' still have {DontEnum} attribute but do not have
{DontDelete} yet. That is not the big problem. The problem is
`__proto__' yet is not mimic of internal [[Prototype]]. The previous
state of prototype chain cannot be restored.

var obj = {};
obj.__proto__ = null;
obj.__proto__ = Object.prototype;

window.alert(Object.prototype.isPrototypeOf(obj)); //false

I use `obj.__proto__ = null;` to create short prototype chain and when
I want to do some things over own properties of that object. For
example, enumerate only own properties, without examine whole
prototype chain for properties which are not have {DontEnum}
attribute. And of course that save me of calling `hasOwnProperty` on
each iteration.

I use workaround with intermediate object in prototype chain.

var obj = {},
     proto = obj.__proto__;
obj.__proto__ = {__proto__ : null};
// Do something with own properties
obj.__proto__ = proto; // Restore previous state of prototype chain

Is this behavior is a bug in SpiderMonkey? I do not found any
information about that. Perhaps the readers of c.l.js can explain why
they implement that in this way.

Thanks for responses.

Yeah, it was mentioned here before: <URL:
http://groups.google.com/group/comp.lang.javascript/msg/f24941a8738be30d>,
although, without explanations (just the fact that it is so) where it
is bug or not.

Also, notice, that this special null assigning kills all other "magic"
properties such as "__parent__" or "__count__".

SM has special case of js "null" handling in this case: <URL:
http://mxr.mozilla.org/mozilla/source/js/src/jsobj.c#270> and at
resolution (and enumeration) then this case somehow bubbles.

This chunk also can be interested: <URL: http://mxr.mozilla.org/mozilla/source/js/src/jsapi.c#2896>

Also, we can't trust to "hasOwnProperty" method in this case. Because,
it says that:

var o = {__count__: 10, x: 100};

o.__count__; // 10
o.hasOwnProperty("__count__"); // true

delete o.__count__;

o.__count__; // 1 - again "magic" count is working
o.hasOwnProperty("__count__"); // but - also true

By the way, in Rhino there is no such behavior; you can assign "null"
to "__proto__" and back any object and it works.

Dmitry.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,817
Latest member
DicWeils

Latest Threads

Top