1.原型链继承
原型链继承是比较常见的继承方式之一,其中涉及的构造函数、原型和实例,三者之间存在着一定的关系,即每一个构造函数都有一个原型对象,原型对象又包含一个指向构造函数的指针,而实例则包含一个原型对象的指针
举个例子
function Parent() {
this.name = 'parent1';
this.play = [1, 2, 3]
}
function Child() {
this.type = 'child2';
}
Child1.prototype = new Parent();
console.log(new Child())
缺点:
- 多个实例对引用类型的操作会被篡改。
2.构造函数继承
借助 call 调用Parent函数
function Parent(){
this.name = 'parent1';
}
Parent.prototype.getName = function () {
return this.name;
}
function Child(){
Parent1.call(this);
this.type = 'child'
}
let child = new Child();
console.log(child); // 没问题
console.log(child.getName()); // 会报错
缺点:
- 只能继承父类的实例属性和方法,不能继承原型属性/方法
- 无法实现复用,每个子类都有父类实例函数的副本,影响性能
3.组合继承
前面我们讲到两种继承方式,各有优缺点。组合继承则将前两种方式继承起来
function Parent3 () {
this.name = 'parent3';
this.play = [1, 2, 3];
}
Parent3.prototype.getName = function () {
return this.name;
}
function Child3() {
// 第二次调用 Parent3()
Parent3.call(this);
this.type = 'child3';
}
// 第一次调用 Parent3()
Child3.prototype = new Parent3();
// 手动挂上构造器,指向自己的构造函数
Child3.prototype.constructor = Child3;
var s3 = new Child3();
var s4 = new Child3();
s3.play.push(4);
console.log(s3.play, s4.play); // 不互相影响
console.log(s3.getName()); // 正常输出'parent3'
console.log(s4.getName()); // 正常输出'parent3'
缺点:
- 会执行两次父类的构造函数,造成多构造一次的性能开销
4.原型式继承
这里主要借助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方法实现的是浅拷贝,多个实例的引用类型属性指向相同的内存,存在篡改的可能
5.寄生式继承
寄生式继承在上面继承基础上进行优化,利用这个浅拷贝的能力再进行增强,添加一些方法
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()); // parent5
console.log(person5.getFriends()); // ["p1", "p2", "p3"]
其优缺点也很明显,跟上面讲的原型式继承一样
6.寄生组合式继承
寄生组合式继承,借助解决普通对象的继承问题的 Object.create 方法,在前面几种继承方式的优缺点基础上进行改造,这也是所有继承方式里面相对最优的继承方式
function Parent(name) {
this.name = name;
this.say = () => {
console.log(111);
};
}
function Children(name) {
Parent.call(this);
this.name = name;
}
Children.prototype = Object.create(Parent.prototype);
Children.prototype.constructor = Children;