原型是JS中继承的基础。JS的继承主要是通过原型链来实现的。用图表示:原型链:使一个原型对象等于另一个类型的实例,递进,这就构成了实例和原型的链式继承原型链继承:子类的原型等于类的实例parentclassfunctionParent(){this.color='blue'//this.getParentValue=function(){//returnthis.color//}}//将方法添加到原型中,避免方法被重复添加到每次添加new时,都会浪费内存=function(){returnthis.childColor}constexp=newChild()console.log('pColor:',exp.getParentValue(),'color:',exp.getChildValue());//pColor:蓝色:yellow优点:继承构造函数及其原型的所有属性和方法。缺点:1.创建子类实例时,无法向父类构造函数传递参数,继承单一。 2。所有新实例都将共享父类实例的属性。(原型上的属性是共享的,如果一个实例修改了原型引用类型的属性,那么另一个实例的原型属性也会被修改!)functionParent(){this.info={name:"lin",age:42}}functionChild(){this.childinfo={name:"meng",age:18}}Child.prototype=newParent()constexp=newChild()exp.info.name="qqqq"constexp1=newChild()console.log('info',exp1.info);//info{name:'qqqq',age:42}构造函数继承:在子类内部调用父类,改变父类通过调用这样做的优点:可以在子类构造函数中将参数传递给超类型构造函数。缺点:只继承父类构造函数的属性,不继承父类原型的属性。functionParent(){this.info={name:'lin',age:42}}functionChild(){Parent.call(this)}constexp1=newChild()exp1.info.name='qqqqq'控制台.log('exp1.info',exp1.info);//exp1.info{name:'qqqqq',age:42}constexp2=newChild()console.log('exp2.info',exp2.info);//exp2.info{name:'lin',age:42}组合继承:原型链+构造函数使用原型链实现原型属性和方法的继承,使用构造函数实现实例属性的继承.这样既通过在原型上定义方法实现了函数的复用,又保证了每个实例都有自己的属性。缺点:调用父类构造函数两次。functionParent(name){this.name=name;this.colors=['red','blue','green']}Parent.prototype.sayName=function(){console.log('Pname',this.name);}functionChild(name,age){Parent.call(this,name)this.age=age}Child.prototype=newParent()//Child.prototype.constructor=ChildChild.prototype.sayAge=function(){console.log('Cage:',this.age);}constexp1=newChild('lin',18)exp1.colors.push('black')console.log('exp1.colors',exp1.colors);//exp1.colors(4)['red','blue','green','black']exp1.sayName()//Pnamelinep1.sayAge()//Cage:18constexp2=newChild('meng',20)console.log('exp2.colors',exp2.colors);//exp2.colors(3)['red','blue','green']问:为什么要设置原型.constructor?A:原型链的建立主要依赖proto属性,所以构造函数对原型链没有影响。prototype.constructor只能用于标识哪个构造函数初始化了对象,仅此而已。原型继承:Object.create()创建一个原型指向对象的构造函数,然后调用new操作符创建一个实例,并返回实例,本质上是一个浅拷贝,引用类型的数据是共享的functionnewObj(o){constObject=function(){}Object.prototype=oreturnnewObject()}constobj={name:"lin",age:18,skills:['js','之间的不同实例java'],show:function(){return`${this.name},${this.age}`}}constobj2=newObj(obj)obj2.skills.push('c')console.log('obj2.skills',obj2.skills);//obj2.skills(3)['js','java','c']constobj3=newObj(obj)//obj3.skills(3)['js','java','c']console.log('obj3.skills',obj3.skills);寄生继承:在原型继承的基础上进行封装,在对象上扩展新的方法,functionnewerObj(o){constObj=Object.create(o)Obj.sayName=function(){returnthis.name}returnObj}constobj={name:"lin",age:18,skills:['js','java'],显示:function(){return`${this.name},${this.age}`}}constobj2=newerObj(obj)console.log('obj2',obj2.sayName());//obj2linparasitic组合继承:借用构造函数继承属性,仅通过原型链继承方式调用超类(父类)构造,并避免在子类原型上创建不必要和冗余的属性函数Inherit(child,parent){constprotoT=Object.create(parent.prototype)protoT.constructor=childchild.prototype=protoT}//使用函数Parent(name){this.name=name,this.colors=['red','blue','green']}Parent.prototype.sayName=function(){console.log('Pname',this.name);}functionChild(name,age){Parent.call(this,name)this.age=age}Inherit(Child,Parent)Child.prototype.sayAge=function(){console.log('Cage',this.age);}constexp1=newChild('lin',18)exp1.colors.push('black')console.log('exp1',exp1);//exp1Child{name:'lin',colors:Array(4),age:18}constexp2=newChild('meng',20)console.log('exp2',exp2);//exp2Child{name:'meng',colors:Array(3),age:20}开发者普遍认为寄生组合继承是最理想的继承范例
