Skip to content Skip to sidebar Skip to footer

Extend Already Defined Class In Javascript

The traditional way of extending classes in JS is something like this: // define constructor function function Fuu(){} // extend prototype and override prototype's constructor Fuu.

Solution 1:

You want something like

            ┌──> Fuu.prototype
instances ──┤
            └──> OtherClass.prototype

But that's not possible, because objects only have one [[Prototype]].

Therefore, you must achieve one of these:

instances ───> Fuu.prototype ───> OtherClass.prototype
instances ───> OtherClass.prototype ───> Fuu.prototype

So you must set the [[Prototype]] of one of those to be the other one. I will assume the first possibility.

There are two main ways to set the [[Prototype]]:

  • Object.create, when creating the object

    The problem is that both Fuu.prototype and OtherClass.prototype have been created already.

    However, you can create a new object with the right [[Prototype]] and assign the properties of the old one.

    Since there may be non-enumerable properties, you must use getOwnPropertyNames. Using defineProperty and getOwnPropertyDescriptor may also be a good idea, in case there are getters or setters.

    var old = Fuu.prototype,
        props = Object.getOwnPropertyNames(old);
    Fuu.prototype = Object.create(OtherClass.prototype);
    for(var i=0; i<props.length; ++i)
       Object.defineProperty(
         Fuu.prototype,
         props[i],
         Object.getOwnPropertyDescriptor(old, props[i])
       );
    
  • setPrototypeOf or __proto__ (ES6), once the object has been created:

    Object.setPrototypeOf(Fuu.prototype, OtherClass.prototype);
    
    Fuu.prototype.__proto__ = OtherClass.prototype;
    

    However, be aware that

    Mutating the [[Prototype]] of an object is, by the nature of how modern JavaScript engines optimize property accesses, a very slow operation, in every browser and JavaScript engine. The effects on performance of mutating prototypes [...] may extend to any code that has access to any object whose [[Prototype]] has been mutated. If you care about performance you should avoid mutating the [[Prototype]] of an object.

Solution 2:

I think the method you have suggested is probably the bet way to go. Is there a reason why you think it is wrong?

var old = Fuu.prototype;
Fuu.prototype = Object.create(OtherClass.prototype, {
    constructor: {
        value: Fuu, 
        enumerable: false, 
        writable: true, 
        configurable: true
    }
});
var names = Object.getOwnPropertyNames(old);
for (var i = 0; i < names.length; i++) {
    var name = names[i];
    Fuu.prototype[name] = old[name];
}

The only thing I'd be concerned about is your constructor method being overridden by the old version, and for your old prototype's prototype chain being lost; however you can do things to fix this.

Post a Comment for "Extend Already Defined Class In Javascript"