JavaScript编码之路【ES6新特性之Class类】(一):https://developer.aliyun.com/article/1556686
二. ES6类的继承
2.1. extends关键字
假设有一种神奇的魔法,它能在父母(Person类)和孩子(Student类)之间架起一座神秘的桥梁。这座桥允许孩子从父母那里获得并流传至子孙的知识(属性)、技能(方法)。这就是ES6为俺们引入的extends关键字【其实在ES5中也是可以实现继承的方案,但是过程却依然是非常繁琐的】:
class Person { } class Student extends Person { }
Student类通过extends关键字借由魔法桥从Person类那里继承了特性和能力。
接下来,小菜鸡就把这个故事讲细一点:
每个人都有自己的姓名和年龄,同样地,每个Person实例也有自己的name和age属性。他们可以跑步和吃东西,因此有running和eating方法。
class Person { constructor(name, age) { this.name = name this.age = age } running() { console.log(this.name + " running~") } eating() { console.log(this.name + " eating~") } }
然后有一种特别的人,他们是学生。他们继承了人的特性,但他们还有自己的特殊之处,比如他们有学生号
,所以Student
类有自己的sno
属性。他们不仅能跑步和吃东西,还需要学习,所以有studying
方法。但最神奇的魔法就在于,他们继承了他们的父辈的所有特性和能力。
class Student extends Person { constructor(name, age, sno) { super(name, age) this.sno = sno } studying() { console.log(this.name + " studying~") } } var stu = new Student("why", 18, 111)
在Student构造函数中,魔法师调用了super函数【下面会详细介绍】。这个super就如同一个魔法传送门,它将孩子带到父母那里,让孩子的属性和父母一样。如果你的类继承了其他类,那么super就必须在this之前被调用,因为它实际上会创建出this【换句话说,super负责创建this,然后你才能对this做赋值操作。这就是为什么在constructor方法中,你必须首先调用super,然后才能使用this关键字。如果你试图在调用super之前使用this,JavaScript会抛出一个引用错误】。
看,我们已经成功创建了一个Student实例,他的名字是why,18岁,学号是111。他能跑步、吃东西,还能学习,因为他继承了Person类,并添加了自己的特性studying。
2.2. super关键字【魔法棒】
这是一段来自 CodeWhy 王元红老师的温馨提示⚡
【注意:在子(派生)类的构造函数中使用this或者返回默认对象之前,必须先通过super调用父类的构造函数!】
super的使用位置有3
个
- 子类的构造函数
- 实例方法
- 静态方法
想象一下,super关键字是一个拥有神奇力量的魔法棒。一旦你挥舞它,神奇的事情就会发生:你的子类就能像父亲一样,拥有父类的属性和方法。这可真是其非凡之处!
首先,让我们看一下super怎么使用。一般情况下,我们会在子类的构造函数、实例方法、静态方法中找到它。
// 调用 父对象/父类 的构造函数 super([arguments]) // 调用 父对象/父类 上的方法 super.functionOnParent([arguments])
如果你在子类的构造函数中使用this,或者没有调用super就要返回对象,那你将会得到一个错误信息。一定要记得,使用super关键字才会调用父类构造函数并且创建出this。
class Person { } class Student extends Person { constructor(sno) { // ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor } } var stu = new Student()
其中,super在实例方法或静态方法中调用父类方法的能力,使我们可以很方便地实现方法的重写。
class Person { eating() { console.log(this.name + " eating~") } static create() { console.log("Person create") } } class Student extends Person { // 方法的重写 eating() { console.log("做完作业~") super.eating() } static create() { super.create() console.log("Student create") } } var stu = new Student() stu.eating() Student.create()
--- 控制台 --- 做完作业~ undefined eating~ Person create Student create
如上为Student类
重写了eating
和create
方法。但在新方法中,我们依然调用了Person
中的eating
和create
方法。这就好像孩子在观察从父亲那里学到的技能之后,找到自己独特的使用方式。
2.3. 继承内置类
在我们已经知道如何继承自定义的类之后,我们同样也可以选择继承JavaScript内置的类,例如Array。这就像我们有能力把超级英雄的超能力赋予给我们的角色,让他能够飞翔、变身或者制造能量光束。
class HYArray extends Array { lastItem() { return this[this.length-1] } } var array = new HYArray(10, 20, 30) console.log(array.lastItem()) array.filter(item => { console.log(item) })
如上创建了一个新类HYArray,它继承自Array类。这就好像我们的角色继承了超级英雄的能力。在HYArray增加了一个新方法lastItem,能够返回数组的最后一个元素。这么做,咱们的角色除了能做超级英雄能做的事情,还能做一些超级英雄做不到的事情。
同时,咱们可以继续改进HYArray类,令它使用filter方法返回的数组还是原来的Array,而不是HYArray。只需要在HYArray类中添加一个Symbol.species方法而已。这个方法返回该构造函数用来创建派生对象的默认构造函数。
class HYArray extends Array { lastItem() { return this[this.length-1] } static get [Symbol.species]() { return Array } } var array = new HYArray(10, 20, 30) console.log(array.lastItem()) var newArr = array.filter(item => { console.log(item) }) console.log(newArr instanceof HYArray) // false console.log(newArr instanceof Array) // true
现在HYArray
就如同一个超级英雄,他不仅继承了父类的能力,还能够做一些其他超级英雄做不到的事情!
小结
参考代码全部来自 CodeWhy 王元红老师 【来源微信公众号 CodeWhy 】,感谢我的引路人王老师。