Reputation: 90
I have this class
class MyClass {
constructor(name, health, damage){
INamable(this)
IHealth(this)
IDamage(this)
IAttack(this)
ITakeDamage(this)
this.setName(name)
this.setHealth(health)
this.setDamage(damage)
}
attack(target){
target.takeDamage(this.getDamage());
}
takeDamage(damage){
this.setHealth(this.getHealth() - damage);
if(this.getHealth()<=0){
this.die();
}
}
toString(){
return "myClassToString"
}
}
// some of the interfaces (methods)
function IAttack(object){
let attack = function(){}
object.attack = attack;
}
function ITakeDamage(object){
let takeDamage = function(){}
object.takeDamage = takeDamage;
}
My question is why does attack(target)
and takeDamage(damage)
don't override the methods inherited in the constructor. I know this may be asked before but I can't find it sorry.
Upvotes: 2
Views: 150
Reputation: 8376
Up in the comments, @Bergi made an assumption that you might be instantiating new MyClass objects in the run time and refer to them. Because you try to change a method of an instance of an MyClass object, and not its prototype, all new instances of MyClass (create with "new" keyword) will still inherit original MyClass's properties.
For example, consider a class Fruit
class Fruit {
constructor() {
this.pieces = 1;
}
cutIntoPieces(pieces) {
this.pieces = pieces;
return this;
}
}
and a function f
that takes any object and changes its property cutIntoPieces
, setting it to a function that unconditionally returns null and does nothing else:
const f = object => {
object.cutIntoPieces = () => null;
};
Let's play around with it a bit in Node REPL:
> banana = new Fruit();
Fruit { pieces: 1 }
> orange = new Fruit();
Fruit { pieces: 1 }
> papaya = new Fruit();
Fruit { pieces: 1 }
> f(banana);
undefined
> banana.cutIntoPieces(2);
null
> banana
Fruit { pieces: 1, cutIntoPieces: [Function] }
> orange.cutIntoPieces(3);
Fruit { pieces: 3 }
> papaya.cutIntoPieces(4);
Fruit { pieces: 4 }
You can see that calling f
on banana changed its behavior when you want to cut it into pieces. This happened because now bananas has its own property cutIntoPieces
, which is a function that unconditionally returns null and doesn't affect the object.
To redefine the method cutIntoPieces
in all instances of the object, we need to change it in their prototype, which is Fruit:
> Object.getPrototypeOf(banana);
Fruit {}
To make such a function that takes a prototype of an object and changes a property of it, so that all instances of that object inherit the changed property, we need to remake our function f
a bit. Let's declare another function and call it g
:
const g = object => {
object.cutIntoPieces = function (cuts) {
this.pieces = 2 ** cuts;
return this;
};
};
Here, g
redefined the method cutIntoPieces
of any object to make cutting more efficient. Now, if we call g
with Fruit.prototype, it will change the method cutIntoPieces
of orange and papaya:
> g(Fruit.prototype);
undefined
> orange.cutIntoPieces(4);
Fruit { pieces: 16 }
> papaya.cutIntoPieces(10);
Fruit { pieces: 1024 }
What's up with banana then?
> banana.cutIntoPieces(2);
null
> banana
Fruit { pieces: 1, cutIntoPieces: [Function] }
Because we called f
on banana, banana.cutIntoPieces
is now not related to Fruit.prototype.cutIntoPieces
. While orange and papaya have this method inherited from the prototype, banana has its own:
> orange.cutIntoPieces === Fruit.prototype.cutIntoPieces
true
> papaya.cutIntoPieces === Fruit.prototype.cutIntoPieces
true
> banana.cutIntoPieces === Fruit.prototype.cutIntoPieces
false
Which is fine, I guess. In case you only want to change behavior of one instance, you can define its own property, its own method; on the other hand, when you need to change behavior of all instances that have methods inherited from prototype, you can change their prototype.
But how to get banana behave identically to other fruit when cut into pieces? Let's delete its own cutIntoPieces
!
> delete banana.cutIntoPieces
true
> banana
Fruit { pieces: 1 }
> banana.cutIntoPieces(2)
Fruit { pieces: 4 }
See, after you remove object's own property, another one, with the same name, is inherited from the prototype, when there is one:
> banana.cutIntoPieces === Fruit.prototype.cutIntoPieces
true
Now banana, orange and papaya behave identically.
Hope it helps and best of luck!
Upvotes: 5