1、原型链继承
缺点: 多个实例对引用类型的操作会被篡改。
2、 借用构造函数
缺点:
- 只能继承父类的实例属性和方法,不能继承原型属性/方法
- 无法实现复用,每个子类都有父类实例函数的副本,影响性能
3、组合继承
缺点:在使用子类创建实例对象时,其原型中会存在两份相同的属性/方法
4、原型式继承
缺点: 原型链继承多个实例的引用类型属性指向相同,存在篡改的可能。
无法传递参数
5、寄生式继承
核心:在原型式继承的基础上,增强对象,返回构造函数
缺点(同原型式继承):
- 原型链继承多个实例的引用类型属性指向相同,存在篡改的可能。
- 无法传递参数
6、寄生组合式继承
结合借用构造函数传递参数和寄生模式实现继承
function inheritPrototype(sub, superT) {
var prototype = Object.create(superT.prototype); //创建对象,创建父类原型的一个副本
prototype = sub; // 增强对象,弥补因重写原型而失去的默认constructor属性
sub.prototype = prototype; //指定对象,将新创建的对象赋值给子类的原型
}
//父类初始化实例属性和原型属性
function SuperT(name) {
this.name = name;
this.food = ['rice', 'drink', 'apple'];
}
SuperT.prototype.sayName = function () {
alert(this.name)
}
// 借用构造函数传递增强子类实例属性(支持传参和避免篡改)
function Sub(name, age) {
SuperT.call(this, name);
this.age = age;
}
// 将父类原型指向子类
inheritPrototype(Sub, SuperT);
Sub.prototype.sayAge = function () {
alert(this.age);
}
// 新增子类原型属性
var instance1 = new Sub('ttt', 32)
var instance2 = new Sub('mmm', 22)
instance1.food.push('bread');
instance2.food.push('milk');
console.log(instance1.food);
console.log(instance2.food);
运行结果:
这个例子的高效率体现在它只调用了一次SuperT构造函数,并且因此避免了在Sub.prototype 上创建不必要的、多余的属性。于此同时,原型链还能保持不变;因此,还能够正常使用instanceof 和isPrototypeOf()
7、混入方式继承多个对象
function MyClass() {
SuperClass.call(this);
OtherSuperClass.call(this);
}
// 继承一个类
MyClass.prototype = Object.create(SuperClass.prototype);
// 混合其它
Object.assign(MyClass.prototype, OtherSuperClass.prototype);
// 重新指定constructor
MyClass.prototype.constructor = MyClass;
MyClass.prototype.myMethod = function() {
// do something
};
Object.assign会把 OtherSuperClass原型上的函数拷贝到 MyClass原型上,使 MyClass 的所有实例都可用 OtherSuperClass 的方法。
8、ES6类继承extends
参考:https://juejin.cn/post/6844903696111763470