目前的class继承主要实现了以下继承效果
1、原型链继承
2、静态属性继承
3、调用父类构造函数以获得父类构造函数this上的属性
Class 可以通过extends
关键字实现继承,这比ES5通过修改原型链实现继承,要清晰和方便很多。
// 继承
class Father {
constructor (name, age, sex) {
this.name = name
this.age = age
this.sex = sex
}
eat () {
console.log("我会吃饭");
}
}
class Son extends Father {
constructor (name, age, sex, height, width) {
// 子类必须在constructor方法中调用super方法,否则新建实例时会报错。
super(name, age, sex)
this.heightValue = height
this.widthValue = width
}
playTheGame () {
console.log("我会打游戏");
}
learning () {
console.log("我会学习");
}
}
const father = new Father("张三", 42, 'man')
const son = new Son('张四', 18, 'man', '180cm', '56kg')
console.log(father); // {name: '张三', age: 42, sex: 'man'}
console.log(son); // {name: '张四', age: 18, sex: 'man', heightValue: '180cm', widthValue: '56kg'}
上面代码定义了一个Father类和Son类,Son类通过extends关键字,继承了Father类的所有属性和方法。
super关键字,它在这里表示父类的构造函数,用来新建父类的this对象。
子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用super方法,子类就得不到this对象。
父类的静态方法,也会被子类继承。
class Father {
static person = '张三'
constructor () {}
static hi() {
console.log('你好');
}
}
class Son extends Father {
constructor () {}
}
Son.hi() // 你好
console.log(Son.person); // 张三
上面代码中,hi()
是Father类的静态方法,Son继承Father,也继承了Father的静态方法。
static——用来声明变量。
Object.getPrototypeOf
方法可以用来从子类上获取父类。因此,可以使用这个方法判断,一个类是否继承了另一个类。
Object.getPrototypeOf()
方法的返回值就是它继承的父类
console.log(Object.getPrototypeOf(Son) === Father); // true
super这个关键字,既可以当作函数使用,也可以当作对象使用。在这两种情况下,它的用法完全不同。
第一种情况,super作为函数调用
第一种情况,super作为函数调用时,代表父类的构造函数。ES6 要求,子类的构造函数必须执行一次super函数。
子类B的构造函数之中的super(),代表调用父类的构造函数。这是必须的,否则 JavaScript 引擎会报错。
class A {}
class B extends A {
constructor() {
// super()在这里相当于A.prototype.constructor.call(this)
super();
}
}
第二种情况,super作为对象
第二种情况,super
作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。
class Father {
static person = '张三'
constructor () {}
hi() {
return "hi"
}
static latiao () {
return "李世民"
}
}
class Son extends Father {
constructor () {
super()
}
he() {
console.log(super.hi() + '你好!'); // hi你好!
}
static food () {
console.log(super.latiao());
}
}
// 在静态方法中,指向父类。
Son.food() // 李世民
// 在普通方法中,指向父类的原型对象
const son = new Son()
son.he() // hi你好!
这里需要注意,由于super指向父类的原型对象,所以定义在父类实例上的方法或属性,是无法通过super调用的。
大多数浏览器的 ES5 实现之中,每一个对象都有__proto__属性,指向对应的构造函数的prototype属性。Class 作为构造函数的语法糖,同时有prototype属性和__proto__属性,因此同时存在两条继承链。
class A {
static hi() {
console.log("hi");
}
}
class B extends A {}
B.__proto__ === A // true
B.prototype.__proto__ === A.prototype // true
console.dir(A);
console.dir(B);
(1)子类的__proto__
属性,表示构造函数的继承,总是指向父类。
(2)子类prototype
属性的__proto__
属性,表示方法的继承,总是指向父类的prototype
属性。