1.原型链的继承//原型链继承/***核心:使用父类的实例作为子类的原型*优点:方法重用*由于方法定义在父类的原型上,构造方法父类的重用,比如say方法*缺点:*创建子类实例时,不能给父类传递参数*子类实例共享父类构造函数的引用属性,比如arr属性*不能实现多重继承****/functionParent(name){this.name=name||'parentclass'//实例的基本属性(这个属性强调私有,不共享)this.arr=[1]//这个属性强调私有,不共享}Parent.prototype.say=function(){//原型对象上定义的方法(强调复用,需要共享)console.log('hello')}functionChild(like){this.like=like}Child.prototype=newParent()//Core,此时Child.prototype.constructor===Parentconsole.log(Child.prototype.constructor===Parent)//true//一个完整的原型对象必须有构造函数Child.prototype.constructor=Child//修正构造函数指向toletboy1=newChild()letboy2=newChild()//优点:共享父类构造函数的say方法console.log(boy1.say())//helloconsole.log(boy2.say())//helloconsole.log(boy1.say()===boy2.say())//true//缺点1不能给console传参。log(boy1.name)//父类console.log(boy2.name)//父类console.log(boy1.name===boy2.name)//true//缺点2子类实例arrboy1.arr.push(2)等父类的共享引用属性//修改boy1的arr,影响boy2的arrconsole.log(boy2.arr)//[1,2]2.借用构造函数继承//借用构造函数继承/***核心:借用父类的构造函数来增强子类的实例,相当于把父类的实例属性复制给子类*优点*1、可以传参*2、子类实例不可以shared父类的引用属性*3、通过调用继承多个父类可以实现多重继承***缺点*1、不能复用父类的方法*因为父类的方法在constructor,方法不能复用,每次创建实例都会生成一个方法*2,子类实例,不能继承父类原型的属性,不使用原型**/functionParent(name){this.name=名称||'parentclass'//instance的基本属性(这个属性强调私有,不共享)this.arr=[1]//这个属性强调私有,不共享this.say=function(){console.log('hello')}}functionChild(name,like){Parent.call(this,name)this.like=like}letboy1=newChild('小红','apple')letboy2=newChild('小明','orange')//优点1可以传参console.log(boy1.name)//小红console.log(boy2.name)//小明//优点2,不共享父类boy1的引用属性.arr.push(2)console.log(boy1.arr,boy2.arr)//[1,2][1]//缺点1不能共享父类的方法console.log(boy1.say===boy2.say)//false表示方法不同//缺点2没有继承父类原型上的方法Parent.prototype.walk=function(){console.log('walk')}boy1.走;//未定义3.CombinedInheritance/***核心:通过调用父类的构造函数,继承父类的属性,保留传参的优点;*然后使用父类实例作为子类原型,实现函数复用*优点:*1.保留构造函数的优点:创建子类实例,可以给父类构造函数传递参数。*2.保留原型链的好处:父类的实例方法定义在父类的原型对象上,可以实现方法复用。*3.不共享父类的引用属性。比如arr属性*缺点:*由于父类的构造函数被调用了两次,所以会出现多余的父类实例属性***/functionParent(name){this.name=name;//实例的基本属性(该属性强调private,不shared)this.arr=[1];//(这个属性强调private)}Parent.prototype.say=function(){//---需要重用和共享的方法定义在父类的原型上console.log('hello')}functionChild(name,like){Parent.call(this,name,like)//核心第二次this.like=like;}Child.prototype=newParent()//核心第一次letboy1=newChild('Xiaohong','apple')letboy2=newChild('Xiaoming','orange')//优点1:可以传参console.log(boy1.name,boy1.like);//小红,apple//优势二:父类原型上的方法可以复用console.log(boy1.say===boy2.say)//true//优势三:不共享引用属性父类的,比如arr属性boy1.arr.push(2)console.log(boy1.arr,boy2.arr);//[1,2][1]不共享arr属性。console.log(boy1.constructor);//Parent你会发现实例的构造函数是Parent。Child.prototype.constructor=孩子;4.组合继承的优化//Core://这样就把父类的实例属性砍掉了,这样在调用父类的构造函数时,就不会再初始化两次实例了,规避弊端的组合继承。//优点://1.只调用一次父类构造函数。//2.保留构造函数的好处:创建子类实例时,可以向父类构造函数传递参数。//3.保留原型链的好处:父类的实例方法定义在父类的原型对象上,可以实现方法复用。//缺点://1.修正了构造函数的指针后,父类实例的构造函数指针也变了(这是我们不希望的)functionParent(name){this.name=name;//实例基本属性(这个属性,强调私有,不共享)this.arr=[1];//(这个属性,强调private)}Parent.prototype.say=function(){//---需要重用,共享方法定义在父类的原型上console.log('hello')}functionChild(name,like){Parent.call(this,name,like)//核心this.like=like;}Child.prototype=Parent.prototype//核心子类原型和父类原型,本质相同letboy1=newChild('小红','apple')letboy2=newChild('小明','orange')letp1=newParent('小爸爸')//优点一:可以传参console.日志(boy1.name,boy1.like);//小红,apple//优点2:console.log(boy1.say===boy2.say)//true//缺点1:当子类构造函数指针固定时,父类实例的构造函数指针也会改变。//具体原因:因为继承是通过原型实现的,所以Child.prototype上没有constructor属性,所以会向上查找,从而找到Parent.prototype上的constructor属性;当你修改子类实例的构造函数属性时,构造函数的所有指针都会改变。//修复前:console.log(boy1.constructor);//Parent//Fix代码:Child.prototype.constructor=Child//Fix后:console.log(boy1.constructor);//Childconsole.log(p1.constructor);//Child是这里的问题(我们希望它是Parent)5.寄生组合继承---完美方式functionParent(name){this.name=name;//实例的基本属性(this属性,强调private,notshared)this.arr=[1];//(这个属性,强调private)}Parent.prototype.say=function(){//---定义父级需要复用和共享的方法console.log('hello')}functionChild(name,like){Parent.call(this,name,like)//核心this.like=like;}Child.prototype=Object.create(Parent.prototype)//核心将通过创建中间对象、子类来隔离原型和父类原型。不一样的,有效避免了方法4的缺点。child.prototype.constructor=Childletboy1=newChild('小红','apple')letboy2=newChild('小明','orange')letp1=newParent('小爸爸')//注:这个方法还修复了构造函数的//修复代码:Child.prototype.constructor=Child//修复后:console.log(boy1.constructor);//Childconsole.log(p1.constructor);//父完美
