JS基础-全方面掌握继承 (3)

以下是Object.create()的模拟实现,使用Object.create()可以达成同样的效果,基本上现在都是使用Object.create()来做对象的原型继承。

function cloneObject(obj){ function F(){} F.prototype = obj; // 将被继承的对象作为空函数的prototype return new F(); // 返回new期间创建的新对象,此对象的原型为被继承的对象, 通过原型链查找可以拿到被继承对象的属性 }

PS:上面Object.create()实现原理可以记一下,有些公司可能会让你讲一下它的实现原理。

例子: let oldObj = { p: 1 }; let newObj = cloneObject(oldObj) oldObj.p = 2 console.log('oldObj newObj', oldObj, newObj)

原型式继承

原型式继承优缺点:

优点: 兼容性好,最简单的对象继承。

缺点:

因为旧对象(oldObj)是实例对象(newObj)的原型,多个实例共享被继承对象的属性,存在篡改的可能。

无法传参

寄生式继承(封装继承过程)

创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后返回对象。

function createAnother(original){ var clone = cloneObject(original); // 继承一个对象 返回新函数 // do something 以某种方式来增强对象 clone.some = function(){}; // 方法 clone.obkoro1 = '封装继承过程'; // 属性 return clone; // 返回这个对象 }

使用场景:专门为对象来做某种固定方式的增强。

寄生组合式继承(call+寄生式封装) 寄生组合式继承原理:

使用借用构造函数(call)来继承父类this声明的属性/方法

通过寄生式封装函数设置父类prototype为子类prototype的原型来继承父类的prototype声明的属性/方法

function fatherFn(...arr) { this.some = '父类的this属性'; this.params = arr // 父类的参数 } fatherFn.prototype.fatherFnSome = '父类原型对象的属性或者方法'; function sonFn() { fatherFn.call(this, '借用构造继承'); // 核心1 借用构造继承: 继承父类通过this声明属性和方法至子类实例的属性上 this.obkoro1 = '子类的this属性'; } // 核心2 寄生式继承:封装了son.prototype对象原型式继承father.prototype的过程,并且增强了传入的对象。 function inheritPrototype(son, father) { const fatherFnPrototype = Object.create(father.prototype); // 原型式继承:浅拷贝father.prototype对象 father.prototype为新对象的原型 son.prototype = fatherFnPrototype; // 设置father.prototype为son.prototype的原型 son.prototype.constructor = son; // 修正constructor 指向 } inheritPrototype(sonFn, fatherFn) sonFn.prototype.sonFnSome = '子类原型对象的属性或者方法' const sonFnInstance = new sonFn(); console.log('寄生组合式继承子类实例', sonFnInstance) 寄生组合式继承子类实例

寄生组合式继承子类实例

寄生组合式继承是最成熟的继承方法:

寄生组合式继承是最成熟的继承方法, 也是现在最常用的继承方法,众多JS库采用的继承方案也是它。

寄生组合式继承相对于组合继承有如下优点:

只调用一次父类fatherFn构造函数。

避免在子类prototype上创建不必要多余的属性。

使用原型式继承父类的prototype,保持了原型链上下文不变。

子类的prototype只有子类通过prototype声明的属性/方法和父类prototype上的属性/方法泾渭分明。

ES6 extends继承:

ES6继承的原理跟寄生组合式继承是一样的。

ES6 extends核心代码:

这段代码是通过babel在线编译成es5, 用于子类prototype原型式继承父类prototype的属性/方法。

// 寄生式继承 封装继承过程 function _inherits(son, father) { // 原型式继承: 设置father.prototype为son.prototype的原型 用于继承father.prototype的属性/方法 son.prototype = Object.create(father && father.prototype); son.prototype.constructor = son; // 修正constructor 指向 // 将父类设置为子类的原型 用于继承父类的静态属性/方法(father.some) if (father) { Object.setPrototypeOf ? Object.setPrototypeOf(son, father) : son.__proto__ = father; } }

另外子类是通过借用构造函数继承(call)来继承父类通过this声明的属性/方法,也跟寄生组合式继承一样。

ES5继承与ES6继承的区别:

本段摘自

ES5的继承实质上是先创建子类的实例对象,再将父类的方法添加到this上

ES6的继承是先创建父类的实例对象this,再用子类的构造函数修改this

因为子类没有自己的this对象,所以必须先调用父类的super()方法。

扩展: 为什么要修正construct指向?

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpysjp.html