ES6通过class
语法及其附加功能使JavaScript看起来简单得多。今天,我们将把class
语法功能与继承概念结合起来。我们将看一下JavaScript的ES6中的super
和extends
关键字。学习新功能的最佳方法是通过示例深入研究它。所以,让我们开始吧!
使用 super
and extends
如果我们想用JavaScript扩展一个类,我们可以借助关键字super
进行扩展。让我们看一下如何使用这些关键字的示例。
class Animal {
constructor(name, weight) {
this.name = name;
this.weight = weight;
}
eat() {
return `${this.name} is eating!`;
}
sleep() {
return `${this.name} is going to sleep!`;
}
wakeUp() {
return `${this.name} is waking up!`;
}
}
class Gorilla extends Animal {
constructor(name, weight) {
super(name, weight);
}
climbTrees() {
return `${this.name} is climbing trees!`;
}
poundChest() {
return `${this.name} is pounding its chest!`;
}
showVigour() {
return `${super.eat()} ${this.poundChest()}`;
}
dailyRoutine() {
return `${super.wakeUp()} ${this.poundChest()} ${super.eat()} ${super.sleep()}`;
}
}
function display(content) {
console.log(content);
}
const gorilla = new Gorilla('George', '160Kg');
display(gorilla.poundChest());
display(gorilla.sleep());
display(gorilla.showVigour());
display(gorilla.dailyRoutine());
// OUTPUT:
// George is pounding its chest!
// George is going to sleep!
// George is eating! George is pounding its chest!
// George is waking up! George is pounding its chest! George is eating! George is going to sleep!
上面的代码有2个JavaScript类,分别是Animal和Gorilla。
Gorilla是Animal的子类,它使用的extends
关键字设定一个子类。
但是,super关键字已以两种不同的方式使用。
你们注意到了吗?在Gorilla的构造函数(代码的第23行)中,
super用作“函数”。而Gorilla的showVigour()(第35行)和dailyRoutine()(第39行)方法已将super用作“对象”。
该super
关键字是由于以下原因两种使用方式:
在第23行中,super
关键字被用作function
,它调用父类Animal与传递的参数Gorilla。这是确保Gorilla是Animal实例的关键步骤。
在第35和39行中,super用作引用“Animal ”实例(父类)的“对象”。这里的super关键字用于显式调用父类Animal的方法。
熟悉C#,Java,Python等语言的人几乎可以与所有这些工作原理相关。但是,JavaScript在ES6出现之前并不是那么简单,尤其是对于类而言。那么人们如何在不使用类语法,super和extended关键字的情况下进行编码?还是他们以前从未使用过这些概念,而是突然决定添加它们?让我们找出答案!
传统的JavaScript类
事实是,确实存在面向对象的JavaScript,并使用原型继承来扩展类。让我们看一下完全相同的示例,但使用传统的JavaScript语法。也许这将帮助我们找到隐藏的真相。
function Animal(name, weight) {
this.name = name;
this.weight = weight;
}
Animal.prototype.eat = function() {
return `${this.name} is eating!`;
}
Animal.prototype.sleep = function() {
return `${this.name} is going to sleep!`;
}
Animal.prototype.wakeUp = function() {
return `${this.name} is waking up!`;
}
function Gorilla(name, weight) {
Animal.call(this, name, weight);
}
Gorilla.prototype = Object.create(Animal.prototype);
Gorilla.prototype.constructor = Gorilla;
Gorilla.prototype.climbTrees = function () {
return `${this.name} is climbing trees!`;
}
Gorilla.prototype.poundChest = function() {
return `${this.name} is pounding its chest!`;
}
Gorilla.prototype.showVigour = function () {
return `${Animal.prototype.eat.call(this)} ${this.poundChest()}`;
}
Gorilla.prototype.dailyRoutine = function() {
return `${Animal.prototype.wakeUp.call(this)} ${this.poundChest()} ${Animal.prototype.eat.call(this)} ${Animal.prototype.sleep.call(this)}`;
}
function display(content) {
console.log(content);
}
var gorilla = new Gorilla('George', '160Kg');
display(gorilla.poundChest());
display(gorilla.sleep());
display(gorilla.showVigour());
display(gorilla.dailyRoutine());
// OUTPUT:
// George is pounding its chest!
// George is going to sleep!
// George is eating! George is pounding its chest!
// George is waking up! George is pounding its chest! George is eating! George is going to sleep!
完代码之后,你们必须在思考,等一下,class一词在哪里?构造函数在哪里?甚至没有扩展名和超级关键字的旧JavaScript代码中甚至如何使用继承?这个代码看起来不丑吗?
是的,我知道你们的感觉,我们在同一页面上。不幸的是,JavaScript的基本功能从未改变。无论语言增加了什么功能,它们始终保持不变。使用新的关键字(例如class,Constructor,super)进行扩展,只会在代码中添加语法风味,从而使代码易于阅读且对开发人员友好。
让我解释一下ES6示例中的哪些代码行符合传统的JavaScript示例。
ES6与传统JavaScript代码的比较
以下各节将细分并比较用ES6和传统JavaScript样式编写的代码。
类声明
在下面的代码片段中对类声明进行了比较。
// ES6 style
class Animal {
constructor(name, weight) {
this.name = name;
this.weight = weight;
}
//...
}
// Check Type of ES6 class
typeof Animal // function
// Traditional style
function Animal(name, weight) {
this.name = name;
this.weight = weight;
}
S6中的类声明直接使用class关键字,然后在构造函数中定义实例变量。在传统的JavaScript中,没有class之类的东西。实际上,类实际上是JavaScript中的一个函数(请参阅此代码片段的第11行)。
第3行的构造函数与第14行完全相同。function Animal实际上是此处的构造函数。
Methods
作为Class
的一部分
// ES6 style
class Animal {
// ...
eat() {
return `${this.name} is eating!`;
}
sleep() {
return `${this.name} is going to sleep!`;
}
wakeUp() {
return `${this.name} is waking up!`;
}
// ...
}
// Traditional style
Animal.prototype.eat = function() {
return `${this.name} is eating!`;
}
Animal.prototype.sleep = function() {
return `${this.name} is going to sleep!`;
}
Animal.prototype.wakeUp = function() {
return `${this.name} is waking up!`;
范围从4到14的代码行是Animal类上用于ES6样式的方法。但是,传统上这是不可能的,因为没有像类这样的东西可以很容易地声明方法。在传统的JavaScript中,将方法添加到原型使方法可用于该类。第19至29行是传统JavaScript类的方法。
映射extends
到传统JavaScript
当我们尝试用子类扩展父类时,会出现更大的区别。请参考以下代码段:
// ES6 style
class Gorilla extends Animal {
constructor(name, weight) {
super(name, weight);
}
//...
}
// Traditional style
function Gorilla(name, weight) {
Animal.call(this, name, weight);
}
Gorilla.prototype = Object.create(Animal.prototype);
Gorilla.prototype.constructor = Gorilla;
我们可以看到 extends
关键字负责扩展父类 Animal
到中的子类,但是 super
在此还使用关键字来确保 Animal
类通过 Gorilla
的构造函数,以继承Animal
特征和行为。在这里,super
关键字作为函数调用的Animal
类初始化 Gorilla
。在这里,super
等效于Animal.call(this,…)
。
为了使传统上发生相同的事情,还需要一些其他步骤。必须按照第10行创建子类Gorilla的函数。由于Gorilla要继承Animal的特性和行为,因此必须在Gorilla的构造函数中调用Animal的 构造函数,如第11行所示,这条线与第4行可比,并且做的相同。只有我们需要将“ this”引用显式传递给Animal类,以确保调用来自Gorilla类。
此外,我们需要将Gorilla函数的原型设置为从Animal的原型创建的新对象,如第11行所示。为此,我们将覆盖Gorilla的原型对象。因此,在下面的第15行,我们需要显式设置Gorilla的构造函数。这些步骤负责将Gorilla类设置为Animal类的子类。
将super映射到传统JavaScript
我们已经在以下代码片段中看到了super关键字的一个映射,即第4行和第19行,其中super被用作函数。
// ES6 style
class Gorilla extends Animal {
constructor(name, weight) {
super(name, weight);
}
showVigour() {
return `${super.eat()} ${this.poundChest()}`;
}
dailyRoutine() {
return `${super.wakeUp()} ${this.poundChest()} ${super.eat()} ${super.sleep()}`;
}
// ...
}
// Traditional style
function Gorilla(name, weight) {
Animal.call(this, name, weight);
}
Gorilla.prototype = Object.create(Animal.prototype);
Gorilla.prototype.constructor = Gorilla;
Gorilla.prototype.showVigour = function () {
return `${Animal.prototype.eat.call(this)} ${this.poundChest()}`;
}
Gorilla.prototype.dailyRoutine = function() {
return `${Animal.prototype.wakeUp.call(this)} ${this.poundChest()} ${Animal.prototype.eat.call(this)} ${Animal.prototype.sleep.call(this)}`;
}
根据第8行和第12行,关键字super也可以用作父类的实例,以调用Animal类特定的详细信息。
为了达到同样的效果,在传统样式中,第26和30行显示了它是如何完成的。
该super
实例实际上是ParentClassName.prototype.methodName.call(this, …)
因此,需要编写大量代码来确保显式调用Parent类的方法。
结论
我敢肯定,你们将立即开始使用ES6的类和继承功能,因为您现在知道传统方式提供的复杂程度。此外,Chrome和Firefox到目前为止都支持ES6,但是为了使所有浏览器都支持ES6功能,将需要babel编译器将所有ES6代码转换为ES5代码。
参考
“Super” and “Extends” In JavaScript ES6 - Understanding The Tough Parts
网友评论