一、原型链继承
父类的实例作为子类的原型,子类继承父类的属性和方法。
优点
:简单易懂,代码量少。
缺点: 所有子类实例共享父类的属性和方法,无法在不影响其他实例的情况下进行修改。
function Parent() {
this.name = 'parent';
}
Parent.prototype.sayHello = function() {
console.log('Hello');
}
function Child() {
this.age = 18;
}
Child.prototype = new Parent();
var child = new Child();
console.log(child.name); // parent
child.sayHello(); // Hello
二、构造函数继承
为了解决原型链继承牵一发动全实例的缺点,推出了构造函数的继承。
子类的构造函数中调用父类的构造函数,使用call或者apply继承父类的属性。
优点
:子类可以独立使用父类的属性。
缺点: 子类无法继承父类原型上的属性和方法。
function Parent () {
this.name = name;
}
function Child () {
Parent.call(this);
this.age = age;
}
var child = new Child('child', 18);
console.log(child.name); // child;
console.log(child.age); // 18;
三、组合继承
为了解决上面两个的问题,组合继承应运而生。
它就是将原型链继承和构造函数结合起来的一种方式。
先调用构造函数继承父类的属性,然后再将父类的实例作为子类的原型,实现父类原型上属性和方法的继承。
优点
:既可以使用父类的属性,也可以使用父类的方法。
缺点:调用了两次父类构造函数。
function SuperType (name) {
this.name = name;
this.colors = ['red', 'blue'];
}
SuperType.prototype.sayName = function () {
console.log(this.name);
}
function subType (name, age) {
// 继承属性
SuperType.call(this, name);
this.age = age;
}
// 继承父类的方法
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
alert(this.age);
};
var instance1 = new SubType("Nicholas", 29);
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,black"
instance1.sayName(); //"Nicholas";
instance1.sayAge(); //29
var instance2 = new SubType("Greg", 27);
alert(instance2.colors); //"red,blue"
instance2.sayName(); //"Greg";
instance2.sayAge(); //27
四、原型式继承
通过创建一个临时性的构造函数,将传入的对象作为构造函数的原型,实现属性和方法的继承。
function createObj(obj) {
function F() {}
F.prototype = obj;
return new F();
}
var parent = {
name: 'parent',
sayHello: function() {
console.log('Hello');
}
};
var child = createObj(parent);
console.log(child.name); // parent
child.sayHello(); // Hello
优点
:可以继承一个对象的属性和方法,比较灵活。
缺点: 所有实例都会共享原型对象。
五、寄生式继承
是原型式继承的基础上,增强对象。
先创建一个父类的副本,然后修改这个副本,最后将修改后的副本赋值给子类。
function createObj(obj) {
var clone = Object.create(obj);
clone.sayHi = function() {
console.log('Hi');
}
return clone;
}
var parent = {
name: 'parent',
sayHello: function() {
console.log('Hello');
}
};
var child = createObj(parent);
console.log(child.name); // parent
child.sayHello(); // Hello
child.sayHi(); // Hi
优点
:可以在继承的基础上增加新的方法或属性,比较灵活
缺点: 无法复用父类的构造函数。
六、寄生组合式继承
组合式继承和寄生式继承的结合体。
- 创建一个函数,将函数的原型指向父类。
- 子类的原型指向这个函数(继承父类)。
- 子类的构造函数指向自己(修正子类构造函数指向)。
// 实现继承的核心函数
function inheritPrototype(subType,superType) {
function F() {};
//F()的原型指向的是superType
F.prototype = superType.prototype;
//subType的原型指向的是F()
subType.prototype = new F();
// 重新将构造函数指向自己,修正构造函数
subType.prototype.constructor = subType;
}
// 设置父类
function SuperType(name) {
this.name = name;
this.colors = ["red", "blue", "green"];
SuperType.prototype.sayName = function () {
console.log(this.name)
}
}
// 设置子类
function SubType(name, age) {
//构造函数式继承--子类构造函数中执行父类构造函数
SuperType.call(this, name);
this.age = age;
}
// 核心:因为是对父类原型的复制,所以不包含父类的构造函数,也就不会调用两次父类的构造函数造成浪费
inheritPrototype(SubType, SuperType)
// 添加子类私有方法
SubType.prototype.sayAge = function () {
console.log(this.age);
}
var instance = new SubType("Taec",18)
console.dir(instance)
优点
:最常用的继承模式。
缺点:写法复杂。
ES6继承
class Parent {
constructor(name) {
this.name = name;
}
sayHello() {
console.log('Hello');
}
}
class Child extends Parent {
constructor(name, age) {
super(name);
this.age = age;
}
}
var child = new Child('child', 18);
console.log(child.name); // child
console.log(child.age); // 18
child.sayHello(); // Hello
ES6的继承方式更加简洁明了,通过class和extends关键字可以直接定义父类和子类,使用super关键字调用父类的构造函数和方法。这种方式避免了手动设置原型和构造函数的步骤,更加符合面向对象编程的思想。
参考链接:https://blog.csdn.net/dlcxycg/article/details/131987415