当前位置: 首页 > Web前端 > vue.js

javascript继承

时间:2023-04-01 11:15:20 vue.js

js中的每个类都分为三部分:构造函数内部,在构造函数之外,用于复制实例化对象,通过点语法直接添加,为类所用,实例化对象在其原型上是访问不到的类和实例化对象可以通过其原型链间接访问,原型链由所有实例化对象共享。但是,继承涉及的不止一个对象,而js并没有继承这种已有的机制,它是如何工作的呢?Prototype在JavaScript中,每个构造函数都有一个prototype属性,指向构造函数的原型对象,原型对象中有一个constructor属性返回指向构造函数;每个实例都有一个__proto__属性,当我们使用构造函数创建实例时,实例的__proto__属性指向构造函数的原型对象。1.类式继承//声明父类functionSuperClass(){this.superValue=true;}//为父类添加一个公共方法SuperClass.prototype.getSuperValue=function(){returnthis.superValue;};//声明子类函数SubClass(){this.subValue=false;}//继承父类SubClass.prototype=newSuperClass();//为子类添加公共方法SubClass.prototype.getSubValue=function(){返回this.subValue;};varinstance1=newSubClass();console.log(instance.getSuperValue());//trueconsole.log(instance.getSubValue());//false一般说这种继承方式有两个缺点:类通过其原型prototype实例化父类,继承父类。因此,如果父类中的公共属性是引用类型,那么它会被子类中的所有实例共享,所以当子类的一个实例修改继承自父类构造函数的公共属性时,会直接影响其他A的子类。由于子类的继承是通过其原型prototype实例化父类来实现的,因此在创建子类实例时,无法将参数传递给父类的构造函数,因此也无法实例化父类。父类构造函数内部的属性被初始化。2.构造函数继承//声明父类函数SuperClass(id){this.books=["js","html","css"];this.id=id;}SuperClass.prototype.showBooks=function(){console.log(this.books);};//声明子类函数SubClass(id){SuperClass.call(this,id);}varinstance1=newSubClass(10);varinstance2=newSubClass(11);instance1.books.push("设计模式");console.log(instance1.books);//['js','html','css','设计模式']console.log(instance1.id);//10console.log(instance2.books);//['js','html','css']console.log(instance2.id);//11console.log(instance1.showBooks());//TypeError缺点:SuperClass.call(this,id);是构造函数式继承的本质。由于这种继承方式不涉及prototype原型,所以父类的prototype方法不会被子类继承。而如果要被子类继承,就必须放在构造函数中,这样创建的每个实例都会有一个单独的副本,不能共享,违背了代码重用的原则。3.组合继承//声明父类函数SuperClass(name){this.books=["js","html","css"];this.name=name;}SuperClass.prototype.getName=function(){console.log(this.name);};//声明子类functionSubClass(name,time){SuperClass.call(this,name);this.time=time;}SubClass.prototype=newSuperClass();subClass.prototype.getTime=function(){console.log(this.time);};varinstance1=newSubClass("jsbook",2014);instance1.books.push("设计模式");console.log(instance1.books);//['js','html','css','设计模式']instance1.getName();//jsbookinstance2.getTime();//2014varinstance2=newSubClass("cssbook",2011);控制台日志(instance2.books);//['js','html','css']instance2.getName();//CSSbookinstance2.getTime();//2011Cons:使用构造函数继承时会执行一次父类的构造函数,而在实现子类原型的类继承时会再次调用父类的构造函数,所以会调用两次父类的构造函数.4.原型继承functioninheritObject(o){//声明一个过渡函数对象functionF(){}//过渡对象的原型继承父对象F.prototype=o;//返回transition对象的实例,实例的原型继承父对象returnnewF();}varperson={name:'ming',hobby:['read','game','bike']};varp1=inheritObject(person);console.log(p1.name);//ming是类继承的一种封装,这里也会存在类继承的问题,但是这个方法在F过渡类的构造函数中没有内容,所以开销比较小,好用。如果你认为有必要,你可以缓存F过渡类,而不是每次都创建一个新的过渡类F。当然,这种担心是多余的。随着这种思想的深入,后来出现了Object.create()方法。Object.create()方法创建一个新对象,使用现有对象提供新创建对象的__proto__。MDN链接:https://developer.mozilla.org...5.寄生继承functioninheritObject(o){//声明一个过渡函数对象functionF(){}//过渡对象的原型继承父对象F.原型=o;//返回原型继承父对象的过渡对象实例returnnewF();}//声明基础对象varbook={name:"js",alikeBook:["css","html"],};functioncreateBook(obj){//通过原型继承创建一个新对象varo=new继承对象(对象);//扩展新对象o.getName=function(){console.log(name);};//返回扩展后的新对象returno;}寄生继承是对原型继承的二次封装,在二次封装时对继承的对象进行扩展,使得新创建的对象不仅具有父类中的属性和方法并且还增加了新的属性和方法,这个思路的作用也是为了寄生组合继承模式的实现。使用寄生继承给对象添加函数,会因为不能带函数而降低效率;这类似于构造函数模式。6.寄生组合继承所谓寄生组合继承,是指通过原型链的混合形式,通过借用构造函数和继承方法来继承属性。其背后的思想是:不需要调用父类的构造函数来指定子类型的原型,我们只需要父类原型的副本。本质上,寄生继承是用来继承超类型的原型,然后将结果赋值给子类型的原型。6.1方法一:functioninheritObject(o){//声明一个过渡函数对象functionF(){}//过渡对象的原型继承父对象F.prototype=o;//返回过渡对象的实例,实例的原型继承父对象returnnewF();}functioninheritPrototype(subClass,superClass){//复制父类的一个副本,保存在变量var中p=inheritObject(superClass.prototype);//修正由于重写子类原型导致修改子类的constructor属性p.constructor=subClass;subClass.prototype=p;}//声明父类functionSuperClass(name){this.name=name;this.colors=["red","orange","blue"];}//给父类添加一个public方法SuperClass.prototype.getName=function(){console.log(this.name);};//声明子类函数SubClass(name,time){//构造函数式继承SuperClass.call(this,name);//子类新属性this.time=time;}//寄生继承父类原型inheritPrototype(SubClass,SuperClass);//子类新原型MethodSubClass.prototype.getTime=function(){console.log(this.time);};6.2方法二://声明父类functionSuperClass(name){this.name=name;this.colors=["red","orange","blue"];}//父类增加一个公共方法SuperClass.prototype.getName=function(){console.log(this.name);};//声明子类functionSubClass(name,time){//构造函数式继承SuperClass.call(this,name);//Subclassnewattributethis.time=time;}//继承父类原型(与方法有一点不同)SubClass.prototype=Object.create(SuperClass.prototype);SubClass.prototype.constructor=SubClass;//子类新原型方法SubClass.prototype.getTime=function(){console.log(this.time);};7.ECMAScript2015中引入的ES6继承JavaScript类本质上是JavaScript现有的基于原型的继承语法的语法糖,没有为JavaScript引入新的面向对象的继承模型。——MDNclassAnimal{//构造函数,包含对象的属性constructor(props){this.name=props.name||'未知';}//方法是后面写的eat(){//父类共享方法console.log(this.name+"会吃害虫。");}}//classinheritsclassBirdextendsAnimal{//构造函数constructor(props,myAttribute){//调用实现父类(props)的构造函数super;//相当于让父类的this指向this.type=props.type||“未知”;this.attr=myAttribute;//自己的私有属性}fly(){//自己的私有方法console.log(this.name+"arefriendlytopeople.");}myattr(){//自己的私有方法console.log(this.type+'---'+this.attr);}}//实例化通过newvarmyBird=newBird({name:'LittleSwallow',type:'Egg'},'Bird');myBird.eat();myBird.fly();myBird.myattr();