Reputation: 7795
After watching this video I learned about a nice way to implement inheritance with Javascript: prototypical inheritance. This method uses Object.create/Object.assign to create a new object based on another instance. This seems very interesting given that it is very easy to understand what is going on. For example:
const human = {
species: 'human',
create: function(values) {
const instance = Object.create(this);
Object.assign(instance, values);
return instance;
},
sayName: function() {
console.log(`Hi, my name is ${this.name}`);
},
saySpecies: function() {
console.log(`Hi, I'm a ${this.species}`);
}
}
const musician = human.create({
species: 'musician',
playInstrument: function() {
console.log(`I'm a musician and I play ${this.instrument}`);
}
});
const aHuman = human.create({ name: 'Paul' });
aHuman.sayName();
aHuman.saySpecies();
const aMusician = musician.create({ name: 'David', instrument: 'Guitar' });
aMusician.sayName();
aMusician.saySpecies();
aMusician.playInstrument();
// how to check if musician is an instance of human?
console.log(musician instanceof human);
With the classical inheritance, I can use instanceof
to know if a given object has a given proto in its chain (e.g. musician instanceof Human
).
This is what the proto chain looks like, which seems very similar to the one created with the new
operator.
Question How to achieve the same thing with prototypical inheritance?
Upvotes: 0
Views: 149
Reputation: 7795
@JLRishe's answer works. But if you want to avoid using functions and keep using objects you can implement your own version of instanceof. This code snippet also works:
const human = {
species: 'human',
create: function(values) {
let newObj = Object.create(this);
return Object.assign(newObj, values);
},
instanceof: function(obj) {
if (!Object.getPrototypeOf(this)) {
return false;
}
let isPrototypeOf = (
this === obj ||
Object.getPrototypeOf(this) === obj ||
this === Object.getPrototypeOf(obj) ||
Object.getPrototypeOf(this) === obj.prototype
);
if (!isPrototypeOf) {
isPrototypeOf = this.instanceof.call(Object.getPrototypeOf(this), obj);
}
return isPrototypeOf;
},
sayName: function() {
console.log(`Hi, my name is ${this.name}`);
},
saySpecies: function() {
console.log(`Hi, I'm a ${this.species}`);
}
}
const musician = human.create({
species: 'musician',
playInstrument: function() {
console.log(`I'm a musician and I play ${this.instrument}`);
}
});
const aHuman = human.create({ name: 'Paul' });
aHuman.sayName();
aHuman.saySpecies();
const aMusician = musician.create({ name: 'David', instrument: 'Guitar' });
aMusician.sayName();
aMusician.saySpecies();
aMusician.playInstrument();
var test = {};
console.log(human.instanceof(human));
console.log(musician.instanceof(human));
console.log(musician.instanceof(Object));
console.log(aHuman.instanceof(human));
console.log(aMusician.instanceof(human));
console.log(aHuman.instanceof(musician));
console.log(aHuman.instanceof(Object));
console.log(aMusician.instanceof(musician));
console.log(musician.instanceof(test));
console.log(human.instanceof(test));
console.log(aMusician.instanceof(test));
console.log(aHuman.instanceof(test));
Upvotes: 0
Reputation: 101662
There are two main problems with your attempt:
instanceof
has to be a function, so your types have to be built on top of functions.create
is a type method. sayName
is an instance method.The follow should work as you are expecting.
function Human(){}
Object.assign(Human, {
create: function(values) {
let newObj = Object.create(this.prototype);
return Object.assign(newObj, values);
}
});
Object.assign(Human.prototype, {
species: 'human',
sayName: function() {
console.log(`Hi, my name is ${this.name}`);
},
saySpecies: function() {
console.log(`Hi, I'm a ${this.species}`);
}
});
function Musician(){}
Object.assign(Musician, Human);
Musician.prototype = Human.create({
species: 'musician',
playInstrument: function() {
console.log(`I'm a musician and I play ${this.instrument}`);
}
});
const aHuman = Human.create({ name: 'Paul' });
aHuman.sayName();
aHuman.saySpecies();
const aMusician = Musician.create({ name: 'David', instrument: 'Guitar' });
aMusician.sayName();
aMusician.saySpecies();
aMusician.playInstrument();
// how to check if musician is an instance of human?
console.log(aMusician instanceof Human);
Upvotes: 1
Reputation: 85767
Your code doesn't use inheritance. The only place where a new object is created is in this line:
return Object.assign({}, this, values);
// ^^ here
{}
creates a new object that inherits from Object.prototype
. It's like doing Object.create(Object.prototype)
or new Object()
.
Nothing in your code inherits from human
or musician
.
Upvotes: 1