If I can use obj.constructor.prototype
to access the prototype of an object, then why can't I use obj.constructor.prototype.constructor.prototype
to traverse the prototype chain and have to use Object.getPrototypeOf
?
function MyConstructor()
{
this.prop = 1;
}
var o = new MyConstructor();
console.log(o.constructor.prototype) // MyConstructor
console.log(o.constructor.prototype.constructor.prototype) // MyConstructor?
Shouldn't it return the prototype of MyConstructor which is function() { [native code] }
(in Chrome console)?
All constructors are instances of the global Function
object:
function Foo(){ this.x = 1 }; // Dummy constructor function
console.log(Foo instanceof Function) // => true; Foo is an instance of global Function constructor
All prototypes are instances of the global Object
object:
console.log(Foo.prototype instanceof Object); // => true
When a constructor Foo
is defined, it automatically has a Foo.prototype
object attached to it, which you can think of as a "blank" object that itself, as per the above, inherits from the global Object
object. In other words, the prototype of Foo.prototype
is Object.prototype
:
function Foo(){ this.x = 1 }; // Dummy constructor function
console.log(Foo.prototype); // Foo (object); already exists
console.log(Object.getPrototypeOf(Foo.prototype) === Object.prototype); // => true
Since Foo.prototype
is a blank object, one would expect its constructor to be the global Object
constructor function:
function Foo(){ this.x = 1 }; // Dummy constructor function
console.log(Foo.prototype.constructor) // => function Foo() { this.x = 1; } ??
console.log(Foo.prototype.constructor === Object.prototype.constructor); // => false
However this "blank" object has an explicit self-referential constructor
property that points back to function Foo(){ this.x = 1 }
and overwrites or "masks" the default constructor property you are expecting:
function Foo(){ this.x = 1 }; // Dummy constructor function
delete Foo.prototype.constructor; // Delete explicit constructor property
console.log(Foo.prototype.constructor) // => function Object() { [native code] }
console.log(Foo.prototype.constructor === Object.prototype.constructor); // => true
Therefore you can't use obj.constructor.prototype
recursively to traverse the prototype chain and have to rely on the Object.getPrototypeOf()
method.
Here's a great visual reference.
If I can use obj.constructor.prototype to access the prototype of an object
You can't in general. Consider how this approach works:
var proto = MyConstructor.prototype;
// has an (nonenumberable) property "constructor"
proto.hasOwnProperty("constructor"); // `true`
// that points [back] to
proto.constructor; // `function MyConstructor() {…}`
As you see, that's a circular property structure. When you do
var o = new MyConstructor();
// and access
o.constructor; // `function MyConstructor() {…}`
// then it yields the value that is inherited from `proto`
// as `o` doesn't have that property itself:
o.hasOwnProperty("constructor"); // `false`
But that only works for object like o
that inherit the constructor
property from their prototype object and where that has a useful value with something pointing to the prototype object. Think of
var o = {};
o.constructor = {prototype: o};
Oops. Accessing o.constructor.prototype
yields o
itself here, and it could have been any other nonsensical value. The structure actually is the same as above with MyConstructor.prototype
- and if you access proto.constructor.prototype.constructor.prototype[.constructor.prototype…]
you won't get anything else than just proto
.
then why can't I use
obj.constructor.prototype.constructor.prototype
to traverse the prototype chain and have to useObject.getPrototypeOf
?
Because you're trapped in the circular structure as MyConstructor.prototype
) has that constructor
property itself and not inherited from Object.prototype
. For really getting the next object the true prototype chain, you have to use Object.getPrototypeOf
.
var o = new MyConstructor(); console.log(o.constructor.prototype) // MyConstructor
It should have been MyConstructor.prototype
actually. Chrome console sometimes gets confused at displaying useful titles for unnamed objects though, and is not always correct.
If you get its prototype, it should yield Object.prototype
, and when you get the prototype of the MyConstructor
function itself it should be Function.prototype
. Notice that you can do the latter by MyConstructor.constructor.prototype
again…
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With