Search code examples
javascriptmergeappendprototype

Javascript: How to append the prototype of a function to another one?


How to append the prototype of a function to another one? Something like:

// Foo
function foo(){};
foo.prototype.a = 'hello';

// Bar
function bar(){}
bar.prototype.b = 'world';

// Append Foo's prototype to Bar
bar.appendPrototype(foo);

// Print
console.log(bar.prototype) // -> { a: 'hello', b: 'world' }

Solution

  • You can iterate the props of the source prototype and add each one to the destination's prototype. This assumes that the properties of the src prototype are simple properties that can be copied (like functions or simple values, not objects themselves) which is usually the case. If you want to allow prototype properties that are nested objects themselves, then you need to clone each property. Usually that isn't required so here's the simpler version:

    bar.appendPrototype = function(src) {
        for (var prop in src.prototype) {
            this.prototype[prop] = src.prototype[prop];
        }
    }
    
    bar.appendPrototype(foo);
    

    Prototypes are just objects so you can just copy the properties of one prototype to another.


    Update several years later. This general concept of copying methods from one prototype to another creates what is generally termed a "mixin" where you mix in the methods of one class into another so that you create a new object that has the capabilities of both objects. Here's an interesting article on the topic that helps explain.

    In implementing mixins, one can now use Object.assign() to copy properties from one object to another in one function call rather than writing your own loop.

    You can even do a mixin on classes previously declared with the ES6 class syntax.

    A fairly common example of a mixin is where you already have a class hierarchy (so you can't just inherit) and now you want a leaf class to also be an eventEmitter and have all the capabilities of that emitter. You can "mixin" the EventEmitter object and now your previously declared class also has the capabilities of an EventEmitter. One precaution you need to take (same as when subclassing) is that you need to make sure none of the instance property names conflict between the two object implementations because both the mixin code and your code will be accessing the same core instance object.

    The alternative to a mixin in the above example is to just add a separate EventEmitter object to your leaf class instance data. As in this.emitter = newEventEmitter(). Then, to access the emitter, rather thanthis.emit(...), you would dothis.emitter.emit(...)`. That works too, but is often not as convenient or concise.