LostInCyberSpace LostInCyberSpace - 4 months ago 33
Javascript Question

Hijacking .__proto__

When an object is instantiated, be it a string/function/etc, a

__proto__
property is included. This property seems to be generated by the
__proto__
accessors in
Object.prototype
...

Object.prototype == {
__defineGetter__ : __defineGetter__()
__defineSetter__ : __defineSetter__()
__lookupGetter__ : __lookupGetter__()
__lookupSetter__ : __lookupSetter__()
constructor : Object()
hasOwnProperty : hasOwnProperty()
isPrototypeOf : isPrototypeOf()
propertyIsEnumerable: propertyIsEnumerable()
toLocaleString : toLocaleString()
toString : toString()
valueOf : valueOf()
get __proto__ : __proto__() // getter
set __proto__ : __proto__() // setter
};


I'm wondering if it is possible to hijack this
__proto__
property to execute a code block when an object is instantiated. The idea being to replace the
__proto__
property with a custom property that executes some code before calling the original accessors to create the
__proto__
on the new instance.

If that makes sense! If not here's where I'm up to:

pro = Object.prototype;
tmp = {};
Object.defineProperty(tmp, '__proto__',
Object.getOwnPropertyDescriptor(pro, '__proto__')
);
delete pro.__proto__;
Object.defineProperty(pro, '__proto__',{
get:function(){
console.warn('intercepted Get __proto__');
return tmp.__proto__;
},
set(p){
console.warn('intercepted Set __proto__');
tmp.__proto__ = p;
}
});


Can't tell if it works properly yet but it's only an example to try and show you what I'm trying to achieve.

Answer

I'm wondering if it is possible to hijack this __proto__ property to execute a code block when an object is instantiated.

No. The __proto__ property's accessors aren't called when the object is created. They're only called when you get or set __proto__. You can see what happens when an object is created by looking at the spec:

ObjectCreate (proto [ , internalSlotsList ])

The abstract operation ObjectCreate with argument proto (an object or null) is used to specify the runtime creation of new ordinary objects. The optional argument internalSlotsList is a List of the names of additional internal slots that must be defined as part of the object. If the list is not provided, a new empty List is used. This abstract operation performs the following steps:

  1. If internalSlotsList was not provided, let internalSlotsList be a new empty List.
  2. Let obj be a newly created object with an internal slot for each name in internalSlotsList.
  3. Set obj's essential internal methods to the default ordinary object definitions specified in 9.1.
  4. Set the [[Prototype]] internal slot of obj to proto.
  5. Set the [[Extensible]] internal slot of obj to true.
  6. Return obj.

Recall that __proto__ isn't the object's prototype reference; that's the [[Prototype]] slot in the object, which isn't accessible in code. __proto__ is just a (web-only) means of accessing the value in that slot. (The general way, which also works outside browsers whereas __proto__ officially doesn't, is getPrototypeOf / setPrototypeOf on Object and Reflect.) Also note that not all objects have __proto__ because not all objects inherit from Object.prototype:

var o1 = {};
console.log("__proto__" in o1); // true
var o2 = Object.create(null);   // No prototype
console.log("__proto__" in o2); // false
var o3 = Object.create(o2);     // Has a prototype, but still no link to Object.prototype
console.log("__proto__" in o3); // false

Comments