This example demonstrates that Baz.prototype
, Bar.prototype
, Foo.prototype
and Object.prototype
exist in the prototype chain for object baz
:
class Foo {}
class Bar extends Foo {}
class Baz extends Bar {}
const foo = new Foo();
const bar = new Bar();
const baz = new Baz();
console.log(Baz.prototype.isPrototypeOf(baz));
console.log(Baz.prototype.isPrototypeOf(bar));
console.log(Baz.prototype.isPrototypeOf(foo));
console.log(Bar.prototype.isPrototypeOf(baz));
console.log(Bar.prototype.isPrototypeOf(foo));
console.log(Foo.prototype.isPrototypeOf(baz));
console.log(Foo.prototype.isPrototypeOf(bar));
console.log(Object.prototype.isPrototypeOf(baz));
The isPrototypeOf()
method — along with the instanceof
operator — comes in particularly handy if you have code that can only function when dealing with objects descended from a specific prototype chain; e.g., to guarantee that certain methods or properties will be present on that object.
For example, to execute some code that's only safe to run if a baz
object has Foo.prototype
in its prototype chain, you can do this:
if (Foo.prototype.isPrototypeOf(baz)) {
}
However, Foo.prototype
existing in baz
's prototype chain doesn't imply baz
was created using Foo
as its constructor. For example, baz
could be directly assigned with Foo.prototype
as its prototype. In this case, if your code reads private fields of Foo
from baz
, it would still fail:
class Foo {
#value = "foo";
static getValue(x) {
return x.#value;
}
}
const baz = { __proto__: Foo.prototype };
if (Foo.prototype.isPrototypeOf(baz)) {
console.log(Foo.getValue(baz));
}
The same applies to instanceof
. If you need to read private fields in a secure way, offer a branded check method using in
instead.
class Foo {
#value = "foo";
static getValue(x) {
return x.#value;
}
static isFoo(x) {
return #value in x;
}
}
const baz = { __proto__: Foo.prototype };
if (Foo.isFoo(baz)) {
console.log(Foo.getValue(baz));
}