Appearance
Class Inheritance
In the previous chapters, we explored JavaScript's object model, which is prototype-based. While it offers simplicity, understanding it can be more challenging than traditional class-instance models, and implementing inheritance often requires extensive code to correctly manage the prototype chain.
Is there a simpler way? Yes! The class
keyword was introduced in ES6 to simplify class definitions in JavaScript.
Let's revisit how we implemented Student
using functions:
javascript
function Student(name) {
this.name = name;
}
Student.prototype.hello = function () {
alert('Hello, ' + this.name + '!');
}
Using the new class
keyword, we can define Student
like this:
javascript
class Student {
constructor(name) {
this.name = name;
}
hello() {
alert('Hello, ' + this.name + '!');
}
}
Comparing the two, the class
definition combines the constructor and methods into a single block, avoiding the need for separate prototype assignments like Student.prototype.hello = function () {...}
.
Creating a Student
object remains unchanged:
javascript
let xiaoming = new Student('Ming');
xiaoming.hello();
Class Inheritance
Another significant advantage of using class
is easier inheritance. For example, when deriving PrimaryStudent
from Student
, we no longer need to consider intermediary objects or prototype constructors. We simply use extends
:
javascript
class PrimaryStudent extends Student {
constructor(name, grade) {
super(name); // Remember to call the parent's constructor!
this.grade = grade;
}
myGrade() {
alert('I am at grade ' + this.grade);
}
}
Here, PrimaryStudent
is also defined using the class
keyword, and extends
indicates that it inherits from Student
. The subclass constructor may differ; for instance, PrimaryStudent
requires both name
and grade
, and it calls the parent constructor with super(name)
to initialize the name
property.
PrimaryStudent
automatically inherits the hello
method from Student
, while we define an additional myGrade
method in the subclass.
Difference Between ES6 Classes and Prototype Inheritance
ES6's class
syntax does not change the underlying prototype-based inheritance; it merely simplifies the implementation of the prototype chain that we previously had to write manually. In essence, class
greatly reduces the boilerplate code associated with prototype chains.
Exercise
Now, use the class
syntax to redefine Cat
, making it inherit from the existing Animal
class, and add a method say()
that returns the string 'Hello, xxx!'
:
javascript
class Animal {
constructor(name) {
this.name = name;
}
}
// FIXME:
class Cat extends Animal {
say() {
return 'Hello, ' + this.name + '!';
}
}
// Test:
let kitty = new Cat('Kitty');
let doraemon = new Cat('Doraemon');
if ((new Cat('x') instanceof Animal)
&& kitty
&& kitty.name === 'Kitty'
&& kitty.say
&& typeof kitty.say === 'function'
&& kitty.say() === 'Hello, Kitty!'
&& kitty.say === doraemon.say)
{
console.log('test passed!');
} else {
console.log('test failed!');
}
This exercise requires browser support for ES6 classes. If you encounter a SyntaxError
, please try using a more recent browser.