发布网友 发布时间:2024-09-30 11:06
共1个回答
热心网友 时间:2024-09-30 12:01
JavaScript中的继承方式学js有一段时间了,但是继承这一块看了好多遍都没有记住,这次看完就索性写篇笔记,加深一下记忆,也可以供大家一起参考学习,有什么错误的地方,感谢大家的指出。?
问:JavaScript中有几种继承方式呢??emmm...六种?五种?还是四种来着...
这次记清楚了一共有五种继承方式
盗用构造函数(经典继承方式)
组合继承
原型链式继承
寄生式继承
寄生式组合继承
问:每种继承方式是怎么实现的呢?盗用构造函数基本思路很简单:在子类构造函数中调用父类构造函数。因为毕竟函数就是在特定上下文中执行代码的简单对象,所以可以使用apply()和call()方法以新创建的对象为上下文执行构造函数。
盗用构造函数的一个优点就是可以在子类构造函数中向父类构造函数传参
function?SuperType(name)?{????this.name?=?name????this.sayName?=?function?()?{????????console.log(this.name);????}}function?SubType(name,?age)?{????//??继承?SuperType?并传参????SuperType.call(this,?name);????//实例属性????this.age?=?age}let?instance1?=?new?SubType('zxc',?2)let?instance2?=?new?SuperType('gyx')//?instance1.sayHi()?//??类也不能访问父类原型上定义的方法,因此所有类型只能使用构造函数模式console.log(instance1);??//?SubType?{?name:?'zxc',?sayName:?[Function?(anonymous)],?age:?2?}组合继承组合继承(有时候也叫伪经典继承)综合了原型链和盗用构造函数,将两者的优点集中了起来。基本的思路是使用原型链继承原型上的属性和方法,而通过盗用构造函数继承实例属性。这样既可以把方法定义在原型上以实现重用,又可以让每个实例都有自己的属性。
function?SuperType(name)?{????this.name?=?name????this.colors?=?['red',?'blue',?'green']}SuperType.prototype.sayName?=?function?()?{????console.log(this.name);}function?SubType(name,?age)?{????//继承实例属性????SuperType.call(this,?name)????this.age?=?age}//继承原型方法SubType.prototype?=?new?SuperType()?SubType.prototype.sayAge?=?function?()?{????console.log(this.age);}let?instance1?=?new?SubType('zxc',?'22')instance1.sayName()??//zxcinstance1.sayAge()???//?22let?instance2?=?new?SubType("Greg",?27);console.log(instance2.colors);?//?"red,blue,green"instance2.sayName();?//?"Greg";instance2.sayAge();?//?27原型链式继承原型式继承适用于这种情况:你有一个对象,想在它的基础上再创建一个新对象。你需要把这个对象先传给object(),然后再对返回的对象进行适当修改。
Object.create()方法将原型式继承的概念规范化了这个方法接收两个参数:作为新对象原型的对象,以及给新对象定义额外属性的对象(第二个可选)
let?person?=?{????name:?"Nicholas",????age:?12,????friends:?["Shelby",?"Court",?"Van"]};let?anotherPerson1?=?Object.create(person);anotherPerson1.name?=?'lll'??anotherPerson1.friends.push('zxc')?console.log(anotherPerson1);???//?{?name:?'lll'?}console.log(person.friends);?//[?'Shelby',?'Court',?'Van',?'zxc'?]//?Object.create()的第二个参数与Object.defineProperties()的第二个参数一样:每个新增属性都通过各自的描述符来描述
let?anotherPerson?=?Object.create(person,?{????name:?{????????value:?"Greg"????}});console.log(anotherPerson.name);?//?"Greg"寄生式继承寄生式继承背后的思路类似于寄生构造函数和工厂模式:创建一个实现继承的函数,以某种方式增强对象,然后返回这个对象。
function?createAnother(original)?{????//通过调用函数创建一个对象????let?clone?=?Object(original)????clone.sayHi?=?function?()?{?//?以某种方式增强这个对象????????console.log("hi");????};????clone.sayName?=?function?()?{?//?以某种方式增强这个对象????????console.log(this.name);????};????return?clone;?//?返回这个对象}let?person?=?{????name:?"Nicholas",????friends:?["Shelby",?"Court",?"Van"]};let?anotherPerson?=?createAnother(person);anotherPerson.sayHi();?//?"hi"anotherPerson.sayName();?//?"hi"寄生时组合继承function?SuperType(name)?{????this.name?=?name????this.colors?=?['red',?'blue']}SuperType.prototype.sayName?=?function?()?{????console.log(this.name)}function?SubType(name,?age)?{????SuperType.call(this,?name);?//?第二次调用?SuperType()????this.age?=?age;}SubType.prototype?=?new?SuperType();?//?第一次调用?SuperType()SubType.prototype.constructor?=?SubType;SubType.prototype.sayAge?=?function?()?{????console.log(this.age);};let?instance1?=?new?SubType('zxc',?12)console.log(instance1);在上面的代码执行后,SubType.prototype上会有两个属性:name?和colors。它们都是SuperType的实例属性,但现在成为了SubType的原型属性。在调用SubType构造函数时,也会调用SuperType构造函数,这一次会在新对象上创建实例属性name和colors。这两个实例属性会遮蔽原型上同名的属性。
如图所示,有两组name和colors属性:一组在实例上,另一组在SubType的原型上。这是调用两次SuperType构造函数的结果,好在有办法解决这个问题。
寄生式组合继承通过盗用构造函数继承属性,但使用混合式原型链继承方法。基本思路是不通过调用父类构造函数给子类原型赋值,而是取得父类原型的一个副本。说到底就是使用寄生式继承来继承父类原型,然后将返回的新对象赋值给子类原型。寄生式组合继承的基本模式如下所示:
function?inheritPrototype(subType,?superType)?{????let?prototype?=?object(superType.prototype);?//?创建对象????prototype.constructor?=?subType;?//?增强对象????subType.prototype?=?prototype;?//?赋值对象}这个inheritPrototype()函数实现了寄生式组合继承的核心逻辑。这个函数接收两个参数:子类构造函数和父类构造函数。在这个函数内部,第一步是创建父类原型的一个副本。然后,给返回的prototype对象设置constructor属性,解决由于重写原型导致默认constructor丢失的问题。最后将新创建的对象赋值给子类型的原型。如下例所示,调用inheritPrototype()就可以实现前面例子中的子类型原型赋值:
function?SuperType(name)?{????this.name?=?name;????this.colors?=?["red",?"blue",?"green"];}SuperType.prototype.sayName?=?function?()?{????console.log(this.name);}function?SubType(name,?age)?{????SuperType.call(this,?name)????this.age?=?age;}inheritPrototype(SubType,?SuperType);SubType.prototype.sayAge?=?function?()?{????console.log(this.age);};这里只调用了一次SuperType构造函数,避免了SubType.prototype上不必要也用不到的属性,因此可以说这个例子的效率更高。而且,原型链仍然保持不变,因此instanceof操作符和isPrototypeOf()方法正常有效。寄生式组合继承可以算是引用类型继承的最佳模式。
原文:https://juejin.cn/post/7095290456057053191