28

Given the following code:

function a() {}
function b() {}
b.prototype = new a();
var b1 = new b();

We can stay that a has been added to b's prototype chain. Great. And, all the following are true:

b1 instanceof b
b1 instanceof a
b1 instanceof Object

My question is, what if we don't know the origins of b1 ahead of time? How can we discover the members of its prototype chain? Ideally I'd like an array like [b, a, Object] or ["b", "a", "Object"].

Is this possible? I believe I've seen an answer somewhere on SO that described how to find out just this but I can't for the life of me find it again.

5 Answers 5

7

Well, the prototype link between objects ([[Prototype]]) is internal, some implementations, like the Mozilla, expose it as obj.__proto__.

The Object.getPrototypeOf method of the ECMAScript 5th Edition is what you're needing, but it isn't implemented right now on most JavaScript engines.

Give a look to this implementation by John Resig, it has a pitfall, it relies on the constructor property of engines that don't support __proto__:

if ( typeof Object.getPrototypeOf !== "function" ) {
  if ( typeof "test".__proto__ === "object" ) {
    Object.getPrototypeOf = function(object){
      return object.__proto__;
    };
  } else {
    Object.getPrototypeOf = function(object){
      // May break if the constructor has been tampered with
      return object.constructor.prototype;
    };
  }
}

Remember that this is not 100% reliable, since the constructor property is mutable on any object.

Sign up to request clarification or add additional context in comments.

4 Comments

right like anything in Javascript looking at object properties and trusting what you get is risky :-)
Thanks, but that tells me that a is a prototype of b1 but nothing about b. How can I find that b1 is an instance of b?
Falling back to constructor is not just wrong because of potential prototype tampering, it's completely wrong to begin with because constructor doesn't do what you'd think it would (see comment below). This shows a surprising ignorance of basic JavaScript functionality from Resig; don't use this script. The information about __proto__ and getPrototypeOf is good, though.
So, bobince, is there a solution? What is it?
3

edit — This answer is from 2010, and quite obsolete. Since then the language has added the Object.getPrototypeOf() API, which vastly simplifies the process.


You could use the "constructor" property of the object to find the prototype there, and then chain along that until you reached the end of the rainbow.

function getPrototypes(o) {
  return (function gp(o, protos) {
    var c = o.constructor;
    if (c.prototype) {
      protos.push(c.prototype);
      return gp(c.prototype, protos);
    }
    return protos;
  })(o, []);
}

(maybe) (or maybe not :-) give me a sec) (well crap; I think it's possible but ignore that code)

[edit] wow this is totally blowing my mind - that function's close but not quite right; setting up a chain of prototypes is weird and I'm feeling scared and lonely. I suggest paying attention only to the awesome @CMS above.

2 Comments

constructor gives you the constructor function of the nearest prototype ancestor that hasn't inherited from another constructor prototype. This is almost never what you want. For example in the question's code, b1.constructor is a, not b, and if you derived an object c from b, a c1.constructor would still be a. Normal rule of thumb: Don't use constructor for anything ever. [eta: lol @ ‘scared and lonely’... yes, this is one of those parts of JavaScript that is designed to confuse the hell out of you by doing something that looks useful but is actually a trap.]
Yes, I consider the original question an interesting exercise but it's never something I'd put in code that I expected to actually work. There's a really nice explanation here: mckoss.com/jscript/object.htm
2

Another way to get the prototype chain:

function getPrototypeChain(obj) {
  let prototypeChain = [];
  (function innerRecursiveFunction(obj) {
    let currentPrototype = (obj != null) ? Object.getPrototypeOf(obj) : null;
    prototypeChain.push(currentPrototype);
    if (currentPrototype != null) {
      innerRecursiveFunction(currentPrototype);
    }
  })(obj);
  return prototypeChain;
}

Comments

1

Here is a simple method without recursive function calls

function getProtoChain(o) {
    const ans = []
    let t = o
    while (t) {
        t = t.__proto__
        ans.push(t)
    }
    return ans
}

Here is an example use of this function

class A {}
class B extends A {}
class C extends B {}

console.log(getProtoChain(new C())) // [C: {}, B: {}, A: {}, {}, null]

Comments

0

Suppose you have an object like:

const dog = new Dog('Rex');

To view it's prototype chain, you can run the following code:

function inspectPrototypeChain(obj) {
    let current = Object.getPrototypeOf(obj); // Start at obj's prototype
    while (current) {
        console.log(current.constructor?.name ?? "[Unknown Constructor]");
        current = Object.getPrototypeOf(current);
    }
    console.log(null);
}

inspectPrototypeChain(dog);

Please note that the last element in the chain is null.

3 Comments

Don't use .constructor.name to log an object; not every object has an (own) .constructor property
I have updated the code.
Apart from objects that don't have a .constructor property at all, I meant that this would be rather confusing if it was an inherited constructor.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.