Reputation: 6514
I wanted to try manually walking the prototype chain of a few objects just to see what I find along the way. However, I got stuck on the first one that I tried. Here's the code:
function MyObject() { }
var x = new MyObject();
console.log('--------------------------------------------');
console.log('x.constructor.name: ' + x.constructor.name);
console.log('x.constructor.prototype.constructor.name: ' + x.constructor.prototype.constructor.name);
console.log(x.constructor.prototype === Function.prototype ? 'Good guess.' : 'No, you are wrong.');
console.log(x.constructor === MyObject ? 'Good guess.' : 'No, you are wrong.');
console.log('--------------------------------------------');
The above code results in the following output in the Developer Tools Console of Google Chrome:
--------------------------------------------
x.constructor.name: MyObject
x.constructor.prototype.constructor.name: MyObject
No, you are wrong.
Good guess.
--------------------------------------------
It makes sense that x's constructor is the MyObject function, since x was instantiated using the new keyword on MyObject (this follows from the definition of a constructor). Because of this, I understand the first line of output (note: I started counting lines of output from zero on up). The second line, however, confuses me. I would like to know what MyObject's prototype is. Apparently, it isn't an object of type Function, as indicated by the 3rd line of output, which tells me that I'm wrong. The fourth line of output just reinforces the output from the first line.
On a more general note, I assumed that the correct way to walk the prototype chain of an object would be to go from the object in question to its constructor, and then from the constructor to the constructor's prototype, assuming that this last reference is not null. I assumed that this two-step process (consisting of going to the constructor, and then to the constructor's prototype) should be repeated until a null reference from a constructor to a prototype is reached, thus signifying the end of the prototype chain. This doesn't seem to be working, though, since application of this algorithm to the above scenario just leads to circular references.
In summary, I have two questions:
Edit
I came across a similar question on StackOverflow here, but it doesn't explicity ask the correct way to walk the prototype chain. It does point out the circular references, though...
Upvotes: 8
Views: 922
Reputation: 4101
In Javascript terminology, an object a
's "prototype" refers to the object from which a
inherits properties. The standards-based way to access this is with Object.getPrototypeOf
:
var protoOfA = Object.getPrototypeOf(a);
There's also the old way, non-standard but supported by some browsers:
var protoOfA = a.__proto__;
But if you have a function F, F.prototype
does NOT refer the object from which F inherits anything. Rather, it refers to the object from which instances created by F inherit:
function F() {};
a = new F();
console.log(Object.getPrototypeOf(a) === F.prototype); // true
When you define a function, an object is created to serve as the prototype of instances created by that function, and this new object is stored in the function's prototype
property.
--
Functions behave like objects in many ways (e.g., they can have properties) but they aren't exactly like other objects:
console.log(typeof a); // "object"
console.log(typeof F); // "function"
Their "prototypes" are ill-defined (example run in Chrome) (this is apparently a Chrome-specific behavior)
console.log(Object.getPrototypeOf(F)); // "function Empty() {}"
console.log(Empty); // ReferenceError: Empty is not defined
--
The constructor
property is strange. The interpreter doesn't care about it. MDN says, confusingly:
Returns a reference to the Object function that created the instance's prototype.
Further, you can change the value of constructor
on an object, but this has no effect on what the object is or how it behaves - it's merely descriptive.
--
So, to answer your questions:
Why is x.constructor === x.constructor.prototype.constructor
No good reason. This is arbitrary behavior browsers have converged on.
what kind of an object is x.constructor.prototype, anyway
In this example, t's x
's prototype, the same as Object.getPrototypeOf(x)
. But in general you can't rely on x.constructor
or anything derived from it, because it's arbitrary.
How can the above algorithm be corrected in order to correctly walk the prototype chain for object x?
for (var p = x ; p != null ; p = Object.getPrototypeOf(p)) {
// do something with p
}
Upvotes: 5
Reputation: 454
Yeah, this can be a bit difficult to grasp at first. I cannot do better than provide you some links. These always help me out when I am in trouble.
http://dmitrysoshnikov.com/ecmascript/javascript-the-core/
http://mckoss.com/jscript/object.htm
http://zeekat.nl/articles/constructors-considered-mildly-confusing.html
Q1: For the "why" see the references above. x.constructor.prototype
is x.__proto__
that is the internal "real" prototype of x, at least in your case when no prototype
and constructor
properties were overwritten. It is created the moment you define the function MyObject.
Q2: Unfortunately you cannot do it this way. You can use the __proto__
property where it is supported, but see
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto
Upvotes: 1