- 原型链继承
(将超类(父类)的实例对象 赋值给 子类的原型对象)
- 优点: 简单易于实现
- 缺点
- 不可多继承
- 子类不能向超类传递参数
- 子类实例成员之间共享父类的属性,如果该属性是引用数据类型,子类实例成员之间将相互影响。
- 子类若要声明自己的原型方法需在继承之后
function SuperClass() { this.name = "super"; this.list = []; //被共享,其中一个子类成员push,其他子类实例成员拿到的list 也会随之变化 } SuperClass.prototype.say = function () { console.log("wo shi super"); }; SuperClass.prototype.push = function (p) { this.list.push(p); }; function SubClass() { this.name = "sub"; } SubClass.prototype.say = function () { console.log("wo shi sub"); }; SubClass.prototype = new SuperClass(); //继承父类的实例对象 SubClass.prototype.print = function () { console.log("print sub"); }; const instance1 = new SubClass(); instance1.say(); // wo shi super instance1.push("instance1"); //将影响其他的子类实例成员的list属性 instance1.print(); const instance2 = new SubClass(); console.log(instance2.list); // ["instance1"];
- 借用构造函数继承
(调用父类的构造函数)
- 优点
- 可以多继承
- 子类可以向超类传递参数
- 继承引用类型的属性子类实例成员之间没有影响
- 缺点
- 不能继承原型链上的属性和方法
- 方法定义在构造函数内,不能被复用(每个子类去继承都是新的函数)
function SuperClass(age) { this.name = "super"; this.age = age; // 不能被复用 this.say = function () { console.log("wo shi super"); }; } //不能被继承 SuperClass.prototype.print = function () { console.log("wo shi super"); }; function SubClass() { SuperClass.call(this, 123); } const instance = new SubClass(); console.log(instance.age);
- 原型式继承
(本质是对象的浅复制)
- 优点:简单易于实现
- 缺点: 同原型链继承一样,超类引用类型被子类共享
function CloneObj(o) { const Fn = function () {}; Fn.prototype = o; return new Fn(); } const superObj = { sex: "男", things: ["money", "house"] }; const sub1 = CloneObj(superObj); const sub2 = CloneObj(superObj); sub1.things.push("car"); //将影响其他子类的things属性 console.log(sub2.things); // ["money", "house", "car"]
上面的cloneObj 函数本质上对传入的对象进行了一次浅复制,在传入一个参数的情况下,作用于Object.create()类似.<https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/create>
- 组合继承
(原型链继承 + 借用超类构造函数)
- 优点
- 父类原型方法可以实现复用
- 超类引用类型属性共享 子类间不会相互影响
- 缺点
- 构造函数被调用两次,创建了俩两超类实例
function SuperClass(age) { this.name = "super"; this.age = age; } SuperClass.prototype.say = function () { console.log("wo shi super"); }; function SubClass() { SuperClass.call(this, 123); } SubClass.prototype = new SuperClass(); SubClass.prototype.constructor = SubClass; //重新添加构造函数指向 const instance = new SubClass();
- 寄生式组合继承
(目前最完美的继承实现方式)
function SuperClass(age) { this.name = "super"; this.age = age; } SuperClass.prototype.say = function () { console.log("wo shi super"); }; function SubClass() { SuperClass.call(this, 123); } //继承函数 function inherit(sup, sub) { const Fn = function () {}; Fn.prototype = sup.prototype; sub.prototype = new Fn(); sub.prototype.constructor = sub; // sub.prototype = Object.create(sup.prototype) } inherit(SuperClass, SubClass); const instance = new SubClass();
- es6继承
class SuperClass { constructor(name = "super", age = 123) { this.name = name; this.age = age; } say() { console.log(`wo shi ${this.name}, age is ${this.age}`); } } class SubClass extends SuperClass { constructor(name, age) { super(name, age); //继承超类属性并传递参数 } say() { super.say(); //继承超类方法 } } class SubClass2 extends SuperClass { constructor(name, age) { super(name, age); //继承超类属性并传递参数 } say() { super.say(); //继承超类方法 } } const instance1 = new SubClass("sub1", 345); const instance2 = new SubClass2("sub2", 456); instance1.say(); // wo shi sub, age is 345 instance2.say(); // wo shi sub2, age is 456 console.log(instance1.say == instance2.say); // false