Reputation: 2743
I'm new to ES6 classes and trying to understand how inheritance works in it. I created a parent class Modal
and a child class ChildModal
like this:
class Modal {
constructor(selector, document) {
this.selector = selector;
this.document = document;
}
get title() {
return this._title;
}
set title(title) {
if(!title) {
throw new Error('Original title cannot be empty');
}
this._title = title;
}
defineNewTitle(newContent) {
this.title = newContent + this.title;
}
assignNewTitle() {
$(this.selector).text(this.title);
}
}
var modal = new Modal("#mainTitle");
modal.title = "Standards";
modal.defineNewTitle("JavaScript ");
modal.assignNewTitle();
class ChildModal extends Modal {
constructor(selector, title) {
super(selector, title);
}
defineChildTitle(title) {
this.title = title + this.title;
}
assignChildTitle() {
$(this.selector).text(this.title);
}
}
var child = new ChildModal("#childTitle");
child.defineChildTitle("Wow ");
child.assignChildTitle();
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
<title>Class test</title>
<h1 id="mainTitle">
Main title
</h1>
<h2 id="childTitle">
Child title
</head>
<body>
<script src="Modal.js"></script>
</body>
</html>
I expect the h2 tag being modified to 'Wow JavaScript Standards', but instead it outputs 'Wow undefined'. Why in method defineChildTitle
it does not recognise this.title
? Thought in the childModal
class, this.title
should be 'JavaScript Standardas I've inherited the
Modalclass in the constructor?
enter code here`
Upvotes: 0
Views: 1961
Reputation: 36299
You need to define _title
in your constructor:
class Modal {
constructor(selector, document) {
this.selector = selector;
this.document = document;
this._title = ''
}
}
var child = new ChildModal("#childTitle");
child.title = "JavaScript Standards"
child.defineChildTitle("Wow ");
child.assignChildTitle();
You are currently joining a string
with undefined
which results in undefined
.
Since you are creating two instances, they don't relate to one another, so child.title
isn't the same as modal.title
, so concatenating the two will result in two different strings.
So, you not only need to set the title in modal.title = 'JavaScript Standards'
, but you also must set the same thing to child.title = 'JavaScript Standards'
.
class Modal {
constructor(selector, document) {
this.selector = selector;
this.document = document;
this.title = ' '
}
get title() {
return this._title;
}
set title(title) {
if(!title) {
throw new Error('Original title cannot be empty');
}
this._title = title;
}
defineNewTitle(newContent) {
this.title = newContent + this.title;
}
assignNewTitle() {
$(this.selector).text(this.title);
}
}
var modal = new Modal("#mainTitle");
modal.title = "Standards";
modal.defineNewTitle("JavaScript ");
modal.assignNewTitle();
class ChildModal extends Modal {
constructor(selector, title) {
super(selector, title);
}
defineChildTitle(title) {
this.title = title + this.title;
}
assignChildTitle() {
$(this.selector).text(this.title);
}
}
var child = new ChildModal("#childTitle");
child.title = "JavaScript Standards"
child.defineChildTitle("Wow ");
child.assignChildTitle();
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
<title>Class test</title>
<h1 id="mainTitle">
Main title
</h1>
<h2 id="childTitle">
Child title
</head>
<body>
<script src="Modal.js"></script>
</body>
</html>
Upvotes: 1
Reputation: 10384
Under the hoods, ES5 classes still use prototype.
So, another solution could be change modal.title = "Standards";
to Modal.prototype.title = "Standards";
.
In this way, you won't change the property in the instance, but you will change the value in the prototype (aka the class definition):
class Modal {
constructor(selector, document) {
this.selector = selector;
this.document = document;
}
get title() {
return this._title;
}
set title(title) {
if(!title) {
throw new Error('Original title cannot be empty');
}
this._title = title;
}
defineNewTitle(newContent) {
this.title = newContent + this.title;
}
assignNewTitle() {
$(this.selector).text(this.title);
}
}
var modal = new Modal("#mainTitle");
Modal.prototype.title = "Standards";
modal.defineNewTitle("JavaScript ");
modal.assignNewTitle();
class ChildModal extends Modal {
constructor(selector, title) {
super(selector, title);
}
defineChildTitle(title) {
this.title = title + this.title;
}
assignChildTitle() {
$(this.selector).text(this.title);
}
}
var child = new ChildModal("#childTitle");
child.defineChildTitle("Wow ");
child.assignChildTitle();
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
<title>Class test</title>
<h1 id="mainTitle">
Main title
</h1>
<h2 id="childTitle">
Child title
</head>
<body>
<script src="Modal.js"></script>
</body>
</html>
Upvotes: 0
Reputation: 15218
Class fields such as title, selector, and document are not shared between instances. So when you assign a title to your fist modal
variable, it does not influence any other isntances or classes.
When the ChildModal calls super(selector, title)
, it passes its title argument to the initialiser of Modal
. In the Modal
class, this is then stored in the document
field.
When you then run this.title = title + this.title;
the title field does not have a any value. It is undefined
. Therefore, the title ends up being "Wow" + undefined
, which results in "Wow undefined".
Upvotes: 2