「这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战」。
继承是面向对象语言中的一大特性,主要有两种实现方式:接口继承和实现继承。接口继承只继承接口声明(签名),实现继承则继承函数或者类内容,由于JS中没有接口的概念,所以JS中的继承都属于实现继承,且都依靠原型链,下面来介绍下几种继承。
-
原型链
每个类型构造器中都有一个原型属性,指向一个原型对象,且每个该类型的实例中都有一个 _ _ propt _ _ 属性指向相同的原型对象。这个原型对象是一个其他类型的实例所以可以通过 _ _ proto _ _ 属性指向其他原型对象。这样层层链接就形成一个原型链。
-
组合继承
通过new一个夫类的实例作为子类的原型对象,同时在构造函数中调用父类的构造函数去继承父类属性,再定义自身属性。使用 instanceOf 跟 isPrototypeof() 能够用于识别该继承方式所创建的对象。
childType.prototype = new SuperType()childType.prototype.constructor = ChildTypefunction ChildType(name, age) { SuperType.call(this, name) // stealing constructor this.age = age} -
原型式继承
通过new操作借助一个已有对象创建新对象,而new操作会调用父对象的构造函数,相当于一次浅拷贝,ES5 实现的Object.create()就是原型式继承。
function prototypal(origin) { function F(){}; F.prototype = origin; return new F();}// 顺便手写一个Object.create()function create(origin, properties) { function F() {}; F.prototype = origin; let o = new F(); if (typeof properties === 'object') { Object.defineProperties(o, properties) } return o;} -
寄生继承
代加工厂模式:在构造函数中调用原型式继承创建一个新对象并加上自身的属性方法,返回新对象,类似高阶组件的思想,缺点为函数不能复用。
-
寄生组合继承
结合寄生继承跟组合继承,避免了组合继承中调用两次父类构造函数,在子类原型上创建不必要的属性方法,被认为是引用类型继承的最理想继承方式。
fucntion parasiticCombin(ChildType, SuperType) { let prototype = Object.create(SuperType.prototye); //寄生继承一个父类的原型对象 prototype.constructor = ChildType; //组合继承 ChildType.prototype = prototype; // 组合继承}function ChildType(name, age) { SuperType.call(this, name) // 组合继承}parasiticCombin(ChildType, SuperType)
参考
红宝书第三版第六章第三节