JS实现继承的6种方式

tech2022-08-07  139

JS实现继承的6种方式

1. 原型链继承:

将构造函数的原型设置为另一个构造函数的实例对象,这样就可以继承另一个原型对象的所有属性和方法,可以继续往上,最终形成原型链。
function Wonman(name){ let instance = new People(); instance.name = name || 'wangxiaoxia'; return instance; } let wonmanObj = new Wonman(); 第一个问题是,当实现继承后,另一个原型的实例属性,变成了现在这个原型的原型属性,然后该原型的引用类型属性会被所有的实例共享,这样继承原型引用类型属性的实例之间不再具有自己的独特性了。第二个问题是,在创建子类型的实例时,没有办法在不影响所有对象实例的情况下给超类型的构造函数中传递参数。
优点:

不限制调用方式

简单,易实现

缺点:

不能多次继承

2. 借用构造函数继承:

为了解决原型中包含引用类型值的问题,开始使用借用构造函数,也叫伪造对象或经典继承
function Woman(name){ //继承了People People.call(this); //People.call(this,'wangxiaoxia'); this.name = name || 'renbo' } let womanObj = new Woman();

这种模式的优势就是可以在子类型构造函数中向超类型构造函数传递参数。

存在的问题就是,所有的类型都只能使用构造函数模式(因为超类型的原型中定义的方法对于子类型不可见),因此方法都在构造函数中定义,函数复用就无从谈起了。

优点:

解决了子类构造函数向父类构造函数中传递参数

可以实现多继承(call或者apply多个父类)

缺点:

方法都在构造函数中定义,无法复用

不能继承原型属性/方法,只能继承父类的实例属性和方法

3. 组合继承:

也叫伪经典继承,将原型链和借用构造函数的技术组合到一块。使用原型链实现对原型属性和方法的继承,而通过构造函数来实现对实例属性的继承。
function Cat(name){ Animal.call(this); this.name = name || 'Tom'; } Cat.prototype = new Animal();// 感谢 @学无止境c 的提醒,组合继承也是需要修复构造函数指向的。Cat.prototype.constructor = Cat; // Test Code var cat = new Cat(); console.log(cat.name); console.log(cat.sleep()); console.log(cat instanceof Animal); // true console.log(cat instanceof Cat); // true
特点:
弥补了方式2的缺陷,可以继承实例属性/方法,也可以继承原型属性/方法既是子类的实例,也是父类的实例不存在引用属性共享问题可传参函数可复用
缺点:

调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)

4. 原型式继承:

不自定义类型的情况下,临时创建一个构造函数,借助已有的对象作为临时构造函数的原型,然后在此基础实例化对象,并返回。
function Wonman(name){ let instance = new People(); instance.name = name || 'wangxiaoxia'; return instance; } let wonmanObj = new Wonman();
优点:

不限制调用方式

简单,易实现

缺点:

不能多次继承

5. 寄生式继承:

其实就是在原型式继承得到对象的基础上,在内部再以某种方式来增强对象,然后返回

function createAnother(original) { var clone = object(original); clone.sayHi = function() { alert("hi"); }; return clone; } 思路与寄生构造函数和工厂模式类似。新的对象中不仅具有original的所有属性和方法,而且还有自己的sayHi()方法。寄生式继承在主要考虑对象而不是自定义类型和构造函数的情况下非常有用。由于寄生式继承为对象添加函数不能做到函数复用,因此效率降低。

6. 寄生组合式继承:

通过寄生的方式来修复组合式继承的不足,完美的实现继承

**核心:**通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点

function Cat(name){ Animal.call(this); this.name = name || 'Tom'; } (function(){ // 创建一个没有实例方法的类 var Super = function(){}; Super.prototype = Animal.prototype; //将实例作为子类的原型 Cat.prototype = new Super(); })(); // Test Code var cat = new Cat(); console.log(cat.name); console.log(cat.sleep()); console.log(cat instanceof Animal); // true console.log(cat instanceof Cat); //true
最新回复(0)