Another question re prototpytes

(Please excuse the old technique.)

I am able to add a function to a constructor’s prototype after I create an object, and use the function:

function Thing() {
    this.prop1 = 1;
    this.prop2 = 2;
}
var thing1 = new Thing();
Thing.prototype.change = function () {
    return this.prop1 + this.prop2;
};
alert(thing1.change());//3

I am able to reassign a constructor’s prototype before I create an object, and use the function:

function Thing() {}
var thing1 = new Thing();
Thing.prototype.change = function () {
    return this.prop1 + this.prop2;
};
// ...
function DeluxeThing() {
    this.prop1 = 10;
    this.prop2 = 20;
}
DeluxeThing.prototype = Object.create(Thing.prototype);
var deluxeThing1 = new DeluxeThing();
// ...
alert(deluxeThing1.change());//30

But I am unable to reassign a constructor’s prototype after I create an object, and use the function:

function Thing() {}
var thing1 = new Thing();
Thing.prototype.change = function () {
    return this.prop1 + this.prop2;
};
// ...
function DeluxeThing() {
    this.prop1 = 10;
    this.prop2 = 20;
}
var deluxeThing1 = new DeluxeThing();
DeluxeThing.prototype = Object.create(Thing.prototype);
// ...
alert(deluxeThing1.change());//TypeError: deluxeThing1.change is not a function

Why is the last case so?

Thanks in advance.

The following explanation is a continuation of this previous reply:

In order to understand why the object deluxeThing1 can’t find the method Thing::change() inherited now by class DeluxeThing, we 1st need to know what actually happens behind-the-scenes when we use the operator new:

Unfortunately the new's reference above isn’t explicitly enough on this part:

  1. A new object is created, inheriting from Foo.prototype.

What it forgets to tell us is that in order for an object to inherit from a prototype{} object, it’s gotta assign that to its __proto__ “secret” accessor property:

Therefore right after var deluxeThing1 = new DeluxeThing();, deluxeThing1{}.__proto__ points to DeluxeThing.prototype{}.

Afterwards you end up reassigning a new object to DeluxeThing.prototype{}:
DeluxeThing.prototype = Object.create(Thing.prototype);

However deluxeThing1{}.__proto__ still points to the original DeluxeThing.prototype{}!

That’s why alert(deluxeThing1.change()); fails, b/c the original DeluxeThing.prototype{} doesn’t have any of Thing.prototype{}'s properties.

As a workaround you could replace Object.create() by Object.setPrototypeOf():
Object.setPrototypeOf(DeluxeThing.prototype, Thing.prototype);

However such approach may interfere w/ that object’s performance forever!

For further knowledge on how JS inheritance chain internals work see this:

But again my advice is that you should stop using ancient JS inheritance techniques and simply embrace the modern ES6 keywords class, extends and super.

You can always transpile your code back to ES5 by pasting it on BabelJS.io for deployment:

1 Like