手机版

JavaScript继承和示例代码

时间:2021-09-07 来源:互联网 编辑:宝哥软件园 浏览:

如果你当时真的不能理解一些知识,可以暂时放下,以后看的时候可能就能理解了。

几个月前,手握《JavaScript 高级程序设计(第三版)》,啃完创作对象后,开始啃继承。然而啃完原型链,我再也受不了了,脑子越来越乱。然后我把它扔到一边,继续看后面。现在,利用这个暑假了解一下这种传承,我会整理一下笔记。

原型链接(原型链接)

先看一篇文章,文章作者讲得很好,而且还配有高清地图。哈哈…

链接:【学习笔记】小角度看JS原型链

从原文中摘录几个词

构造器通过原型属性访问原型对象,实例对象通过[[prototype]]内部属性访问原型对象,浏览器为实例对象实现原型属性以访问原型对象。所有对象都是对象的实例,所有函数都是函数的实例。对象是一个构造函数。因为它是函数,所以它是函数的实例对象。函数是构造函数,但函数原型是对象。因为它是一个对象,所以决定原型和实例之间关系的是对象的实例对象

有两种方法可以检测原型和实例之间的关系:

Instanceof:确定该对象是否是另一个对象的实例

instanceof的内部运行机制如下:

functioninstance_of(L,R){//L表示左表达式,R表示右表达式VarO=R . prototype://取r l=l. _ _ prototype _ _//取l while的隐式原型(true) {if (l===null)返回falseIf(O===L)//这里的重点是,当O严格等于L时,返回truereturntrueL=L. _ _ proto _ _}}以上代码摘自:对JavaScript instanceof运算符的深入分析

Isrototypeof():测试一个对象是否存在于另一个对象的原型链中。关于这两种方法的区别,请参见JAVAScript isProtoTypeof vs instance of用法。

只使用原型链实现继承

缺点:1。引用类型值的原型属性将由实例共享;2.创建子类型的实例时,不能将参数传递给超类型的构造函数

function神父(){this.name='神父';this.friends=['aaa ',' BBB '];} function son(){ } son . prototype=new Faird();Son . prototype . constructor=Son;var S1=Newson();var S2=Newson();console . log(S1 . name);//父控制台. log(S2 . name);//父1 . name=' son ';console . log(S1 . name);//sonconsole . log(S2 . name);//父控制台. log(S1 . friends);//['aaa ',' BBB ']console . log(S2 . friends);//['aaa ',' bbb']s1.friends.push('ccc ',' DDD ');console . log(S1 . friends);//['aaa ',' bbb ',' ccc ',' DDD ']console . log(S2 . friends);//['aaa ',' bbb ',' ccc ',' ddd']只使用构造函数实现继承

实现方法:调用子类型构造函数内部的超类型构造函数(使用apply()和call()方法)

优点:解决了原型中引用类型属性的问题,子类可以将参数传递给超类

缺点:子类实例不能访问父类(超类)原型中定义的方法,所以不可能谈函数复用。

函数父亲(姓名,朋友){ this.name=namethis.friends=朋友;}父亲. prototype . getname=function(){ returnthis . name;};FunctionSon(name){//注意:为了确保父构造函数不会覆盖子构造函数的属性,请将调用父构造函数的代码放在Son中定义的属性之前。父亲.呼叫(这个,名字,['aaa ',' BBB ']);this.age=22} vars 1=Newson(' son1 ');vars 2=Newson(' son2 ');console . log(S1 . name);//son1 console . log(S2 . name);//son2s1.friends.push('ccc ',' DDD ');console . log(S1 . friends);//['aaa ',' bbb ',' ccc ',' DDD ']console . log(S2 . friends);//['aaa ',' bbb']//子类实例无法访问父类原型中的方法S1 . getname();//TypeError: s1.getName不是函数2 . getname();//typeerror:s2。getname不是函数组合继承(组合继承)

实现方法:原型链用于继承原型属性和方法,构造函数用于继承实例属性。

函数父亲(姓名,朋友){ this.name=namethis.friends=朋友;}父亲.原型.金钱='10万美元';父亲. prototype . getname=function(){ console . log(this . name);};functionSon(name,age){//继承父类的属性父辈. call (this,name,['AAA ',' BBB '];this.age=年龄;}//继承父类原型中的属性和方法Son.prototype=神父();Son . prototype . constructor=Son;son . prototype . GetAge=function(){ console . log(this . age);};vars1=newSon('son1 ',12);S1 . friends . push(' CCC ');console . log(S1 . friends);//['aaa ',' bbb ',' CCC ']console . log(S1 . money);//10万美元S1 . getname();//son1s 1 . GetAge();//12vars2=newSon('son2 ',24);console . log(S2 . friends);//['aaa ',' BBB ']console . log(S2 . money);//10万美元S2 . getname();//son2s 2 . GetAge();//24组合继承避免了单方面使用原型链或构造函数实现继承的缺陷,结合了两者的优点,成为JavaScript中最常用的继承模式,但也有缺陷,后面会提到。

原型继承(原型继承)

实现思路:在原型的帮助下,基于已有对象创建新对象,不需要创建自定义类型。

为了实现这个目标,引入了以下函数(obj)

function obj(o){ functionF()} { f . prototype=o;returnnewF();}varperson1={ name: 'percy ',friends 3360[' AAA ',' BBB ']};varperson 2=obj(person 1);person 2 . name=' zyj ';person 2 . friends . push(' CCC ');console . log(person 1 . name);//percycon sole . log(person 2 . name);//zyjconsole . log(person 1 . friends);//['aaa ',' bbb ',' CCC ']console . log(person 2 . friends);//['AAA ',' BBB ',' CCC'] ECMAScript 5通过添加Object.create()方法来标准化原型继承。传入参数时,Object.create()和obj()方法的行为相同。varperson1={ name: 'percy ',friends 3360[' AAA ',' BBB ']};varperson 2=object . create(person 1);person 2 . name=' zyj ';person 2 . friends . push(' CCC ');console . log(person 1 . name);//percycon sole . log(person 2 . name);//zyjconsole . log(person 1 . friends);//['aaa ',' bbb ',' CCC ']console . log(person 2 . friends);//['aaa ',' bbb ',' ccc']当不需要创建构造函数,只想保持一个对象与另一个对象相似时,可以选择使用这种继承。

寄生遗传(寄生遗传)

寄生遗传是一种与原型遗传密切相关的思想。

实现思路:创建一个只封装继承过程的函数,通过某种方式在内部增强对象,最后返回对象。

function obj(o){ functionF()} { f . prototype=o;returnnewF();} functioncreateperson(original){//包继承过程var clone=obj(original);//创建对象clone . show something=function(){//增强对象console.log('Hello world!');};returnclone//返回对象{ varperson={ name : ' percent ' };varperson 1=create person(person);console . log(person 1 . name);//percypersona 1 . show SexOry();//你好世界!寄生组合遗传(寄生组合遗传)

先说说我们之前组合继承的缺陷。组合继承最大的问题是,父类的构造函数在任何情况下都会被调用两次:一次是创建子类的原型时,另一次是调用子类的构造函数时,父类的构造函数在子类的构造函数内部被调用。

函数父亲(姓名,朋友){ this.name=namethis.friends=朋友;}父亲.原型.金钱='10万美元';父亲. prototype . getname=function(){ console . log(this . name);};functionSon(name,age){//继承父类的属性父辈. call (this,name,['AAA ',' BBB '];//第二次调用父(),但只有当new Son()时才会调用this.age=age}//继承父类原型中的属性和方法Son.prototype=神父();//第一次调用父亲()son . prototype . constructor=son;第一次调用使子类的原型成为父类的实例,这样子类的原型就获得了父类的实例属性;第二个调用将使子类的实例也获得父类的实例属性;默认情况下,子类的实例属性将屏蔽子类原型中同名的属性。因此,在这两次调用后,子类原型中会出现冗余属性,因此引入寄生组合继承来解决这个问题。

寄生组合继承背后的思想是,我们不必为了指定子类的原型而调用父类的构造函数,我们需要的只是父类原型的副本。

本质上,寄生继承用于继承父类的原型,然后将结果返回给子类的原型。

function obj(o){ functionF()} { f . prototype=o;returnnewF();} functioninheritPrototype(儿子,父亲){varprototype=obj(父亲. prototype);//创建对象原型. prototype.constructor=son//增强对象son.prototype=prototype//return object}函数父亲(姓名、好友){this。name=namethis.friends=朋友;}父亲.原型.金钱='10万美元';父亲. prototype . getname=function(){ console . log(this . name);};functionSon(name,age){//继承父类的属性父辈. call (this,name,['AAA ',' BBB '];this.age=年龄;}//使用寄生继承继承父类原型中的属性和方法inheritPrototype(子,父);son . prototype . GetAge=function(){ console . log(this . age);};vars1=newSon('son1 ',12);S1 . friends . push(' CCC ');console . log(S1 . friends);//['aaa ',' bbb ',' CCC ']console . log(S1 . money);//10万美元S1 . getname();//son1s 1 . GetAge();//12vars2=newSon('son2 ',24);console . log(S2 . friends);//['aaa ',' BBB ']console . log(S2 . money);//10万美元S2 . getname();//son2s 2 . GetAge();//24优点:子类原型避免继承父类中不必要的实例属性。

开发人员普遍认为,寄生组合继承是实现基于类型继承的最佳方式。

最后

最后,我强烈推荐两篇硬文章

JavaScript原型继承如何真正工作JavaScript的伪经典继承图(需要翻墙)

给第二篇文章拍一张硬照:

看完之后,秒针明白了原型链。有木头吗?

以上是继承自JavaScript的数据整理,后续继续补充相关数据。感谢您对本网站的支持!

版权声明:JavaScript继承和示例代码是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。