第一种 原型链继承
function Parent1() {this.name = 'parent1';this.play = [1, 2, 3]}function Child1() {this.type = 'child1';}// ------- 这里通过修改原型链继承Child1.prototype = new Parent1();console.log(new Child1());var s1 = new Child1()var s2 = new Child1()s1.play.push(4)console.log(s1.play, s2.play) // [1,2,3,4] [1,2,3,4]
缺点:原型链方案存在的缺点:多个实例对引用类型的操作会被篡改。
第二种 构造函数继承
function SuperType(){this.color=["red","green","blue"];}function SubType(){// ----- 继承自SuperTypeSuperType.call(this);}var instance1 = new SubType();instance1.color.push("black");alert(instance1.color);//"red,green,blue,black"var instance2 = new SubType();alert(instance2.color);//"red,green,blue"
核心代码是SuperType.call(this),创建子类实例时调用SuperType构造函数,于是SubType的每个实例都会将SuperType中的属性复制一份。
缺点:
- 只能继承父类的实例属性和方法,不能继承原型属性/方法
- 无法实现复用,每个子类都有父类实例函数的副本,影响性能
第三种 组合继承(原型链+构造函数)
```bash function SuperType(name){ this.name = name; this.colors = [“red”, “blue”, “green”]; } SuperType.prototype.sayName = function(){ alert(this.name); };
function SubType(name, age){ // 继承属性 // 第二次调用SuperType() SuperType.call(this, name); this.age = age; }
// 继承方法 // 构建原型链 // 第一次调用SuperType() SubType.prototype = new SuperType(); // 重写SubType.prototype的constructor属性,指向自己的构造函数SubType 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,green,black” instance1.sayName(); //“Nicholas”; instance1.sayAge(); //29
var instance2 = new SubType(“Greg”, 27); alert(instance2.colors); //“red,blue,green” instance2.sayName(); //“Greg”; instance2.sayAge(); //27
缺点:属性在原型链上有叠加,删除当前实例的属性,但是原型链上还有。<a name="FXUhS"></a># 第四种:原型式继承```bash// 利用一个空对象作为中介,将某个对象直接赋值给空对象构造函数的原型function object(obj){function F(){}F.prototype = obj;return new F();}
缺点:
- 原型链继承多个实例的引用类型属性指向相同,存在篡改的可能。
- 无法传递参数
第五种:寄生式继承
使用原型式继承可以获得一份目标对象的浅拷贝,然后利用这个浅拷贝的能力再进行增强,添加一些方法,这样的继承方式就叫作寄生式继承。
虽然其优缺点和原型式继承一样,但是对于普通对象的继承方式来说,寄生式继承相比于原型式继承,还是在父类基础上添加了更多的方法。那么我们看一下代码是怎么实现 ```bash 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()); console.log(person5.getFriends());
<a name="n5TIf"></a># 第六种:寄生组合式继承```bashfunction inheritPrototype(subType, superType){var prototype = Object.create(superType.prototype); // 创建对象,创建父类原型的一个副本prototype.constructor = subType; // 增强对象,弥补因重写原型而失去的默认的constructor 属性subType.prototype = prototype; // 指定对象,将新创建的对象赋值给子类的原型}// 父类初始化实例属性和原型属性function SuperType(name){this.name = name;this.colors = ["red", "blue", "green"];}SuperType.prototype.sayName = function(){alert(this.name);};// 借用构造函数传递增强子类实例属性(支持传参和避免篡改)function SubType(name, age){SuperType.call(this, name);this.age = age;}// 将父类原型指向子类inheritPrototype(SubType, SuperType);// 新增子类原型属性SubType.prototype.sayAge = function(){alert(this.age);}var instance1 = new SubType("xyc", 23);var instance2 = new SubType("lxy", 23);instance1.colors.push("2"); // ["red", "blue", "green", "2"]instance1.colors.push("3"); // ["red", "blue", "green", "3"]
第七种 es6 extends super
class A {}class B extends A {constructor() {super(); // ES6 要求,子类的构造函数必须执行一次 super 函数,否则会报错。}}
注:在 constructor 中必须调用 super 方法,因为子类没有自己的 this 对象,而是继承父类的 this 对象,然后对其进行加工,而 super 就代表了父类的构造函数。super 虽然代表了父类 A 的构造函数,但是返回的是子类 B 的实例,即 super 内部的 this 指的是 B,因此 super() 在这里相当于 A.prototype.constructor.call(this, props)
执行父类的constructor,但是绑定的this是当前子类的。
