美文网首页
JavaScript ES6中的“Super”和“Extends

JavaScript ES6中的“Super”和“Extends

作者: 魂斗驴 | 来源:发表于2021-02-08 08:45 被阅读0次

ES6通过class语法及其附加功能使JavaScript看起来简单得多。今天,我们将把class语法功能与继承概念结合起来。我们将看一下JavaScript的ES6中的superextends关键字。学习新功能的最佳方法是通过示例深入研究它。所以,让我们开始吧!

使用 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

相关文章

网友评论

      本文标题:JavaScript ES6中的“Super”和“Extends

      本文链接:https://www.haomeiwen.com/subject/dheotltx.html