Reputation: 73
I have one class that extends another, in the inherited class constructor I am overwriting a property also used in the parent's constructor.
class Animal {
name = "animal";
constructor() {
console.log(this.name);
}
}
class Rabbit extends Animal {
constructor() {
super();
this.name = 'rabbit';
}
}
new Animal(); // shows animal
new Rabbit(); // shows animal
Since at the time the parent's constructor is called the new value is not yet available, it shows "animal" again. I know this is due to the JS internals.
The page where I found the problem says that it can be fixed by using methods or getters/setters instead of fields, but I can't find a way to work around it. How can I make it show the new value?
Upvotes: 2
Views: 328
Reputation: 18639
The thing you might be confused on is where the value is actually logged.
class Animal {
name = "animal";
constructor() {
console.log('In Animal', this.name);
//Here it has the value 'animal', Rabbit's constructor hasn't overwritten it yet
}
}
class Rabbit extends Animal {
constructor() {
super();
this.name = 'rabbit';
console.log('In Rabbit', this.name)
//rabbit as expected
}
}
const rabbit = new Rabbit();
console.log('After constructors', rabbit.name) //still rabbit
If you look at it after the parent constructor had run, it'll show rabbit
.
This is the expected way in most of the cases, as this prevents the child constructor to mess up the properties before the paren't initialization finishes.
To make the parent receive the child's value anyway (like virtual methods, but for properties), you can use getters (the way you've mentioned):
class Animal {
constructor() {
console.log('In Animal', this.name);
//also rabbit
}
get name(){
return 'animal'
}
}
class Rabbit extends Animal {
constructor() {
super();
console.log('In Rabbit', this.name)
//rabbi
}
get name(){
return 'rabbit'
}
}
const rabbit = new Rabbit();
console.log('After constructors', rabbit.name) //rabbit
Upvotes: 1
Reputation: 28434
You can add an optional argument to the constructor
:
class Animal {
constructor(name = "animal") {
this.name = name;
console.log(this.name);
}
}
class Rabbit extends Animal {
constructor() {
super('rabbit');
}
}
new Animal(); // shows animal
new Rabbit(); // shows rabbit
Upvotes: 2
Reputation: 2953
Doing anything in parent constructor with an assumption that it 'knows' anything about classes that extends it is a bad idea, because it leads to close coupling.
A better way to do it is to have a separate function for returning the name:
class Animal {
name = "animal";
sayName() {
console.log(this.name);
}
}
class Rabbit extends Animal {
constructor() {
super();
this.name = 'rabbit';
}
}
new Animal().sayName(); // shows animal
new Rabbit().sayName(); // shows rabbit
Upvotes: 3