It is not very useful to do two assignments to the prototype
property, as the last one will overwrite the first. You can do like this, since Object.assign
accepts more arguments:
Object.assign(ChildClass.prototype, ParentClass1.prototype, ParentClass2.prototype);
Note that Object.assign
performs a shallow copy. That a copy has to be made is sure: you need a prototype object that is different from both other prototypes: the union of both. So inevitably you need to somehow copy the members of the parent prototypes into your target prototype object.
Some caveats:
1. Object.assign
makes a shallow copy
Since Object.assign
performs a shallow copy, you might get into cases where you interfere with the parent prototype. This might be what you want or do not want.
Example:
var ParentClass1 = function() {
};
ParentClass1.prototype.userList = [];
ParentClass1.prototype.addUser = function(name) {
this.userList.push(name);
};
var ParentClass2 = function() {
};
ParentClass2.prototype.askUser = function(name) {
console.log('Hey, how are you,', name);
};
var ChildClass = function(name) {
this.askUser(name);
};
Object.assign(ChildClass.prototype, ParentClass1.prototype, ParentClass2.prototype);
var p = new ParentClass1('Parent');
var obj = new ChildClass('John');
obj.addUser('Tim'); // Added to child, but
console.log(p.userList); // now parent also has Tim...
2. Object.assign
only copies enumerable properties
This means that in some cases you will not get the properties you had hoped for. Say you wanted to inherit also from Array.prototype
, then you would want your child object to have a length
property, but since it is not enumerable, you will not get it with Object.assign
:
var ParentClass2 = function() {
};
ParentClass2.prototype.askUser = function(name) {
console.log('Hey, how are you,', name);
};
var ChildClass = function(name) {
this.askUser(name);
};
Object.assign(ChildClass.prototype, Array.prototype, ParentClass2.prototype);
var obj = new ChildClass('John');
console.log(obj.length); // undefined
console.log(Array.prototype.length); // 0
3. Object.assign
executes getters
Object.assign
cannot copy getters. Instead it executes them to retrieve the value for the copy. Executing code on the parent prototype may have effects (by design of that getter) on the state of the parent prototype. This might be undesired behaviour in the context of this copy.
Secondly, the value of the getter can be the result of some calculation and state of the object, returning different values each time it is referenced. But object.assign
will only reference it once, and then create a property that always has that single value. See the effect in this example:
var ParentClass1 = function() {
};
// Define a getter on the prototype which returns a
// random number between 0 and 999, every time it is referenced:
Object.defineProperty(ParentClass1.prototype, 'randomNumber', {
get: function() {
return Math.round(Math.random() * 1000);
},
enumerable: true
});
var ParentClass2 = function() {};
ParentClass2.prototype.askUser = function(name) {
console.log('Hey, how are you,', name);
};
var ChildClass = function(name) {
this.askUser(name);
};
Object.assign(ChildClass.prototype, ParentClass1.prototype, ParentClass2.prototype);
var p = new ParentClass1('Parent');
var obj = new ChildClass('John');
console.log('different:');
console.log(p.randomNumber);
console.log(p.randomNumber);
console.log(p.randomNumber);
console.log('always same:');
console.log(obj.randomNumber);
console.log(obj.randomNumber);
console.log(obj.randomNumber);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Further reading
The concept of combining multiple prototypes into a new one is often coined "mixin". Here are some related Q&A: