继承是javascript中实现代码复用的一种方式,也可以绑定对象或函数之间的关系。为什么要继承?比如下面的代码,Person、Student和Teacher的构造函数,你可以发现他们有一些特征Person和Student有Name,age属性和eatingmethod,但是Student也有学号,score属性和学习方法Person和Teacher都有有名字,年龄属性和吃法,但老师也有教学法}functionStudent(name,age,sno,score){this.name=namethis.age=agethis.sno=snothis.score=scorethis.eating=function(){console.log('eating')}this.studing=function(){console.log('studing')}}functionTeacher(name,age){this.name=namethis.age=agethis.eating=function(){console.log('eating')}this.teaching=function(){console.log('teaching')}}可以发现在定义函数的时候有很多重复的代码,Person、Student、Teacher是包含关系船。继承就是以这种包含关系为突破口,减少重复代码。父类原型被分配给子类。这种方式是直接将子类和父类原型指向同一个对象Student.prototype=Person.prototype这样会将子元素原型中添加的所有属性和方法都添加到父元素中,并添加另一个子元素,并且它还会有其他子元素的所有方法,这种实现继承的方式不推荐用于原型继承。继承关系可以通过函数的原型属性来实现。也就是说,原型继承就是将Student.prototype赋值给Person的构造函数实例对象图如下:eating')}functionStudent(score){this.score=score}varperson=newPerson()Student.prototype=personvarstudent=newStudent(88)console.log(student)console.log(student.name)控制台.log(student.__proto__)student.eating()上面代码的执行结果是Student的实例对象可以访问Person的属性和方法,但是存在一些问题。通过打印,获取不到Student继承的Person的属性和方法。Person中的属性无法自定义。基于以上问题,构造函数值的继承是基于原型的继承,利用构造函数来解决问题。父函数在子函数中通过call/apply调用functionPerson(name){this.name=name}Person.prototype.eating=function(){console.log('eating')}functionStudent(name,score){Person.call(this,name)this.score=score}varperson=newPerson()Student.prototype=personvarstudent=newStudent('kiki',88)console.log(student)console.log(student.name)console.log(student.__proto__)student.eating()执行结果如下这样可以解决原型继承的存在两个问题,一个是父元素Person的属性和方法可以从Student实例对象中找到,另一个是你可以自定义Person属性的值。但这样的定义也存在一个问题。Person的构造函数至少执行两次,一次是创建Person的实例对象,另外一次是在Student构造函数中通过调用创建Person对象并保存一份Person数据,但是这个数据是不必要的寄生继承寄生继承结合了原型继承和工厂函数,创建一个实现继承的函数,在函数内部操作对象并返回varuser={flying:function(){console.log('flying')}}functioncreateObj(name,age){varobj=Object.create(user)obj.name=nameobj.age=ageobj.eating=function(){console.log('eating')}returnobj}varkiki=createObj('kiki',18)console.log(kiki)console.log(kiki.__proto__)执行结果如下通过寄生继承,解决了需要重复调??用父类函数,保存不必要的数据的问题,但是又产生了新的问题无法知道对象的类型。比如Person或者Student的每个对象都保存了一个吃的方法。其实不需要寄生组合继承,通过一个对象来链接父子函数。继承关系图如下:首先定义一个原型继承函数,提供三种定义方法,可以根据项目兼容性选择varobj={name:'alice'}//方法一:setPrototypeOfffunctioncreateObject1(o){varobj={}Object.setPrototypeOf(obj,o)returnobj}//方法二:构造函数createObject2(o){functionFn(){}Fn.prototype=ovarobj=newFn()returnobj}varobj1=createObject1(obj)varobj2=createObject2(obj)//方法三:Object.createvarobj3=Object.create(obj)console.log(Object.getOwnPropertyDescriptors(obj1.__proto__))console.log(Object.getOwnPropertyDescriptors(obj2.__proto__))console.log(Object.getOwnPropertyDescriptors(obj3.__proto__))执行结果is然后在构造函数的继承关系中加入原型继承函数functioncreateObj(o){functionFn(){}Fn.prototype=oreturnnewFn()}//封装继承函数functioninheritPrototype(subType,superType){subType.prototype=createObj(superType.prototype)Object.defineProperty(subType.prototype,'constructor',{value:subType,configurable:true})}functionPerson(name,age){this.name=namethis.年龄=年龄this.eating=function(){console.log('eating')}}functionStudent(name,age,score){Person.call(this,name,age)this.score=score}inheritPrototype(Student,Person)Student.prototype.running=function(){console.log('running')}varstudent=newStudent('alice',18,100)console.log(student)student.running()执行结果为Parasitic组合继承可以更好的解决上述继承方式存在的问题。原型继承关系实例对象、结构体函数和原型对象之间存在继承关系varobj={}functionFoo(){}varfoo=newFoo()console.log(obj.__proto__===Object.prototype)console.log(foo.__proto__===Foo.prototype)console.log(Foo.__proto__===Function.prototype)console.log(Function.__proto__===Function.prototype)console.log(Object.__proto__===Function.prototype)控制台。log(Foo.prototype.__proto__===Object.prototype)console.log(Function.prototype.__proto__===Object.prototype)console.log(Object.prototype.__proto__)执行结果如下继承关系如下实例对象定义obj的字面值相当于创建一个FunctionObject的实例,所以obj的隐式原型等于Object的显式原型。foo对象是构造函数Foo的实例,因此foo的隐式原型等于Foo的显式原型。Function对象functionFoo也是一个对象,是构造函数Function的一个实例,所以函数Foo的隐式原型等于Function函数Function的显式原型Function也是一个对象,是构造函数Function的一个实例,所以theimplicitprototypeofFunctionisequaltotheexplicitprototypeofFunction,即函数的隐式原型等于显式原型。函数Object也是一个对象,它是构造函数Function的一个实例,所以函数Object的隐式原型等于Function的显式原型prototype。对象Foo的显式原型也是一个对象,它是构造函数Object的一个实例,所以Foo对象的隐式原型的显式原型等于Object的显式原型。Function的显式原型也是一个对象,它是构造函数Object的一个实例,所以Function显式原型的隐式原型等于Object的显式原型。类型原型也是一个对象,其隐式原型指向nulljs继承的方法有五种,原型的继承关系。关于高级js,开发者需要掌握的东西还是很多的。可以看看我写的其他博文,持续更新中~
