原型链继承最常见的继承方式涉及构造函数、原型和实例每个构造函数都有一个原型对象原型对象包含一个指向构造函数的指针,实例包含一个指向原型对象的指针有一个问题这个继承方法functionParent(){this.name="parent"this.own=[1,2,3]}functionChild(){this.type="child"}Child.prototype=newParent()console.log(newChild())//Parent{type:'child'}letc1=newChild();letc2=newChild();c1.own.push(4)console.log(c1.own,c2.own)//[1,2,3,4][1,2,3,4]因为两个实例使用同一个原型对象,内存空间是共享的,当一个发生变化时,另一个也发生了变化相应的Constructor继承使用call来实现functionParent(){this.name="parent"this.own=[1,2,3]}Parent.prototype.getName=function(){returnthis.name;}functionChild(){Parent.call(this)this.type="child"}constchild=newChild()console.log(child)//Child{name:'parent',own:[1,2,3],type:'child'}console.log(child.getName())//child.getName不是函数这种方法解决了原型共享内存的弊端,同时也带来了新的问题。只能继承父类的实例属性和方法,不能继承原型属性或方法。组合继承综合了前两种继承方式的优缺点。组合继承函数Parent(){this.name="parent"this.own=[1,2,3]}Parent.prototype.getName=function(){returnthis.name;}functionChild(){//第二次调用Parent.call(this)this.type="child"}//第一次调用Parent3()Child.prototype=newParent()//手动挂断构造函数并指向到你自己的构造函数Child.prototype.constructor=Child;letc1=newChild()letc2=newChild()c1.own.push(4)console.log(c1.own,c2.own)//[1,2,3,4][1,2,3]console.log(c1.getName())//parentconsole.log(c2.getName())//parentParent执行了两次,第一次是在原型的时候Child改变了,第二次是通过call方法调用Parent时,那么多构造一次Parent会带来额外的性能开销。原型继承使用ES5中的Object.create方法,该方法接收两个参数:一个是作为新对象原型的对象,另一个是为新对象定义附加属性的对象(可选参数)letparent={name:"parent",friend:['1',',2','3'],getName:function(){returnthis.name}}letp1=Object.create(parent)p1.name="杰克"p1.friend.push("a")letp2=Object.create(parent)p1.friend.push("b")console.log(p1.name)//jakeconsole.log(p1.name===p1.getName())//trueconsole.log(p2.name)//parentconsole.log(p1.friend)//['1',',2','3','a','b']console.log(p2.friend)//['1',',2','3','a','b']这种继承方式的缺点很明显,多个实例的引用类型属性指向同一个内存,存在被篡改的可能。寄生遗传。原型继承可以获得目标对象的一个??浅拷贝,然后利用这个浅拷贝的能力来增强和添加一些方法。这种遗传称为寄生。继承的优缺点和原型继承是一样的,但是对于普通的对象继承来说,寄生继承比原型继承给父类增加了更多的方法。letparent={name:"parent",friend:['1',',2','3'],getName:function(){returnthis.name}}functionclone(src){letclone=Object.创建(来源);clone.getFriends=function(){returnthis.friend;};返回克隆;}letp1=clone(parent)console.log(p1.getName())//parentconsole.log(p1.getFriends())//['1',',2','3']添加getFriends方法,使得p1这个普通对象在继承过程中又增加了一个方法,仍然有两次调用父类的构造函数,造成寄生组合继承的浪费。这种继承方式的缺点可以更好的达到继承的预期效果,同时减少构造次数,降低性能开销。functionclone(parent,child){//这里使用Object.create减少组合继承多构造一次的过程child.prototype=Object.create(parent.prototype)child.prototype.constructor=child;}functionParent(){this.name="parent"this.friend=['1',',2','3']}Parent.prototype.getName=function(){returnthis.name}functionChild(){Parent.call(this)this.friend="labor"}clone(Parent,Child)Child.prototype.getFriends=function(){returnthis.friend}letc1=newChild()console.log(c1)//Child{name:'parent',friend:'labor'}console.log(c1.getName())//parentconsole.log(c1.getFriends())//extendsinlaborES6也用到了这种分类方法没有使用构造函数继承和原型链继承的Object.create方法。它们使用原型继承和寄生继承的Object.create方法组合成复合继承。基于此,就有了寄生联合遗传。类似于ES6扩展
