一、原型链继承
- 优点:所有实例共享一个原型对象
- 缺点:
- 1.因为父类已经实例化了,所以在创建子类时无法通过子类传递参数给父类构造函数
- 2.所有实例共享一个原型对象,当原型中存在引用类型的数据时,一个实例对其修改会影响到所有实例
function Parent() {
this.colors = ['red', 'yellow']
}
function Son() { }
Son.prototype = new Parent()
Son.prototype.constructor = Son
const son1 = new Son()
const son2 = new Son()
son1.colors.push('pink')
console.log('son2', son2.colors);
二、借用构造函数继承
- 优点:
- 1.实例化子类时,可以通过子类传递参数给父类
- 2.每个实例的成员互不影响,解决引用数据共享的问题
- 3.构造函数复用,借用构造函数继承允许子类构造函数调用父类构造函数,实现对父类函数的复用
- 缺点:
- 1.只能继承父类的属性和方法,无法继承父类的原型
- 2.无法实现复用,每个子类都有父类实例函数的副本(实例化时都调用父类构造函数,无法复用父类),影响性能
function Parent() {
this.age = 12
}
function Son() {
Parent.call(this)
}
const son = new Son()
console.log(son);
三、组合继承
- 优点:
- 1.避免了引用数据共享的问题:每个实例都有自己的引用数据副本
- 2.可以通过子类传递参数给父类
- 3.调用了两次构造函数,增加性能开销,因为重复调用,导致定义了重复的属性
function Parent() {
this.age = 12
}
function Son() {
Parent.call(this)
}
Son.prototype = new Parent()
Son.prototype.constructor = Son
四、原型式继承
利用空对象作为中介,将某个对象直接赋值给空对象构造函数的原型
- 缺点:
- 1.原型链继承多个实例的引用数据指向相同,存在篡改的可能
- 2.无法传递参数
function createObject(obj) {
function F() { }
F.prototype = obj
return new F();
}
const person = {
name: '1212',
friends: ['abc', 'def']
}
const p1 = createObject(person)
const p2 = createObject(person)
p1.friends.push('gg')
console.log('p2', p2.friends); // ['abc', 'def', 'gg']
五、寄生式继承
在原型式继承的基础上,增强对象,返回构造函数
- 缺点:与原型式继承一样
- 1.原型链继承多个实例的引用数据指向相同,存在篡改的可能
- 2.无法传递参数
function createAnother(original) {
// 通过原型链继承对象
const obj = Object.create(original)
// 增强对象
obj.sayHi = function () { }
return obj
}
const person = {
name: '1212',
friends: ['abc', 'def']
}
const anotherPerson = createAnother(person)
六、寄生组合式继承
结合借用构造函数传递参数和寄生式继承实现继承
寄生组合式继承避免了组合继承中调用两次超类构造函数的问题,同时保留了原型链的完整性,使得子类能够共享父类原型上的方法。这使得寄生组合式继承成为一种相对高效且常用的继承方式。
function inheritPrototype(child, parent) {
// 创建一个父类原型的副本
const prototype = Object.create(parent.prototype);
// 将副本的构造函数指向子类
prototype.constructor = child;
// 将子类原型指向这个副本
child.prototype = prototype;
}
function Parent(name) {
this.name = name;
this.colors = ["red", "blue", "green"];
}
Parent.prototype.sayHello = function () {
console.log("Hello, " + this.name);
};
function Child(name, age) {
// 借用构造函数继承属性
Parent.call(this, name);
this.age = age;
}
// 寄生组合式继承
inheritPrototype(Child, Parent);
// 子类可以调用超类的方法,并且原型链保持完整
const childInstance = new Child("John", 25);
childInstance.sayHello(); // 输出: Hello, John
console.log(childInstance.colors); // 输出: ["red", "blue", "green"]