这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战
介绍
- 继承可以使子类得到父类的属性和方法,甚至可以重新定义父类的属性。
- 通过重写或覆盖父类的方法,以取得不同于父类的属性和方法
- 继承是面向对象的,可以更好的复用之前的开发代码,缩短开发周期,提高开发效率。
简单回顾
上一篇文章的内容中,我们学习了不适用Object.create()的几种继承方式:
- 原型链继承
- 构造函数继承
- 由原型链继承和构造函数继承两种方式结合出的组合式继承
那接下来就开始学习新的继承内容了。
使用Object.create()
以下方法针对于普通对象。
Object.create 方法,这个方法接收两个参数:一是用作新对象原型的对象、二是为新对象定义额外属性的对象(可选参数)。
原型式继承
let parent4 = {
name: "parent4",
friends: ["p1", "p2", "p3"],
getName: function() {
return this.name;
}
};
let person4 = Object.create(parent4);
person4.name = "tom";
person4.friends.push("jerry");
let person5 = Object.create(parent4);
person5.friends.push("lucy");
console.log(person4.name); // tom
console.log(person4.name === person4.getName()); // true
console.log(person5.name); // parent4
console.log(person4.friends); // ["p1", "p2", "p3", "jerry", "lucy"]
console.log(person5.friends); // ["p1", "p2", "p3", "jerry", "lucy"]
原型式继承,名字听起来似乎和原型链继承方式如出一辙,但是内容却是有很大差别。相对于原型链继承方式来说,代码结构简单了很多,但也有很大缺点:多个实例中引用类型数据的内存也是共享的,存在篡改的可能。
原因就是Object.create是可以用来支持浅拷贝的。所以当实例中的属性值是引用类型数据时,内容共享,会导致发生篡改。
寄生式继承
其原理是:先使用原型式继承可以获得一份目标对象的浅拷贝,然后对浅拷贝对象的能力进行增强,给其添加一些方法,最终将扩展后的对象作为子类使用。
寄生式继承和原型式继承的优缺点相同,但是寄生式继承可以在父类的基础上扩展更多的方法,以便使用更加的灵活一些
let parent5 = {
name: "parent5",
friends: ["p1", "p2", "p3"],
getName: function() {
return this.name;
}
};
function clone(original) {
let clone = Object.create(original);
clone.getFriends = function() {
return this.friends;
};
return clone;
}
let person5 = clone(parent5);
console.log(person5.getName());
console.log(person5.getFriends());
寄生组合式继承
function Parent6() {
this.name = 'parent6';
this.play = [1, 2, 3];
}
Parent6.prototype.getName = function () {
return this.name;
}
function Child6() {
Parent6.call(this);
this.friends = 'child5';
}
function clone (parent, child) {
// 这里改用 Object.create 就可以减少组合继承中多进行一次构造的过程
child.prototype = Object.create(parent.prototype);
child.prototype.constructor = child;
}
clone(Parent6, Child6);
Child6.prototype.getFriends = function () {
return this.friends;
}
let person6 = new Child6();
console.log(person6);{name: "parent6", play: [1,2,3], friends: "child5"}
console.log(person6.getName()); //parent6
console.log(person6.getFriends()); // child5
结合了寄生式继承和组合式继承的优点,通过寄生式继承减少了组合式继承过程中的构造函数调用过程,并且可以在父类的基础上对子类对象进行属性和方法的扩展,基本解决了前几种继承方式的缺点,较好地实现了继承想要的结果,减少了继承过程中性能的开销。
ES6extends继承
class Person {
constructor(name) {
this.name = name
}
// 原型方法
// 即 Person.prototype.getName = function() { }
// 下面可以简写为 getName() {...}
getName = function () {
console.log('Person:', this.name)
}
}
class Gamer extends Person {
constructor(name, age) {
// 子类中存在构造函数,则需要在使用“this”之前首先调用 super()。
super(name)
this.age = age
}
}
const asuna = new Gamer('Asuna', 20)
asuna.getName() // 成功访问到父类的方法
ES6中的extends继承和java的很相似。父类的原型方法写在构造函数之外,而子类想继承父类属性和方法,除了extends关键字之外。还必须在子类的构造函数中通过super()调用才能实现继承,再之后才是对子类对象自己的属性和方法进行定义。