电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

JavaScript 常見的繼承方式匯總

瀏覽:86日期:2023-10-12 17:15:40

原型鏈機制:

在ECMAscript中描述了原型鏈的概念,并將原型鏈作為實現繼承的主要方法,其基本思想就是利用原型讓一個引用類型繼承另一個引用類型的屬性和方法。

構造函數和原型還有實例之間的關系:

每個構造函數都有一個原型對象(prototype),原型對象都包含一個指向構造函數的指針(constructor),而實例都包含一個指向原型對象的內部指針 ( __propto__ ) 。關系圖如下圖所示:

JavaScript 常見的繼承方式匯總

每一個Function都是Object基類的一個實例,所以每一個Function上都有一個__proto__指向了Object.prototype。

當查找一個實例的屬性時,會先從這個實例的自定義屬性上找,如果沒有的話通過__proto__去實例所屬類的原型上去找,如果還沒有的話再通過原型(原型也是對象,只要是對象就有__proto__屬性)的__proto__到Object的原型上去找,一級一級的找,如果沒有就undefined。

所以引用類型之間的繼承就是通過原型鏈機制實現的。

一.原型繼承

原型繼承:把父類的私有+公有的屬性和方法,都作為子類公有的屬性。

核心:不是把父類私有+公有的屬性克隆一份一模一樣的給子類的公有。他是通過__proto__建立和子類之間的原型鏈,當子類的實例需要使用父類的屬性和方法的時候,可以通過__proto__一級級找上去使用。 

function Parent(){ this.x = 199; this.y = 299;}Parent.prototype.say = function(){ console.log(’say’)}function Child(){ this.g = 90;}Child.prototype = new Parent();var p = new Parent();var c = new Child();console.dir(c)

實現的本質是重寫了原型對象 ,通過將子類的原型指向了父類的實例,所以子類的實例就可以通過__proto__訪問到 Child.prototype 也就是 Parent的實例,這樣就可以訪問到父類的私有方法。然后再通過__proto__指向父類的prototype就可以獲得到父類原型上的方法。

這樣就做到了將父類的私有、公有方法和屬性都當做子類的公有屬性。這樣就通過原型鏈實現了繼承。

但是別忘了默認的原型,因為所有引用類型都是繼承了Object的,所有說子類也可以訪問到Object上的方法如toString() 、valueOf() 等。

結果如下圖所示:

JavaScript 常見的繼承方式匯總

有的時候我們需要在子類中添加新的方法或者是重寫父類的方法時候,切記一定要放到替換原型的語句之后。

function Parent(){ this.x = 199; this.y = 299;}Parent.prototype.say = function(){ console.log(’say’)}function Child(){ this.g = 90;}/*Child.prototype.Bs = function(){ console.log(’Bs’)}*/在這里寫子類的原型方法和屬性是沒用的因為會改變原型的指向,所以應該放到重新指定之后Child.prototype = new Parent();Child.prototype.constructor=Child//由于重新修改了Child的原型導致默認原型上的constructor丟失,我們需要自己添加上,其實沒啥用,加不加都一樣Child.prototype.Bs = function(){ console.log(’Bs’)}Child.prototype.say = function(){ console.log(’之后改的’)}var p = new Parent();var c = new Child();console.dir(c)c.Bs() //Bsc.say() // 之后改的p.say() //say 不影響父類實例訪問父類的方法

存在的問題:

1. 子類繼承父類的屬性和方法是將父類的私有屬性和公有方法都作為自己的公有屬性和方法,我們要清楚一件事情就是我們操作基本數據類型的時候操作的是值,在操作應用數據類型的時候操作的是地址,如果說父類的私有屬性中引用類型的屬性,那他被子類繼承的時候會作為公有屬性,這樣子類一操作這個屬性的時候,會影響到子類二。

2. 在創建子類的實例時,不能向父類型的構造函數中傳遞參數。應該說是沒有辦法在不影響所有對象實例的情況下,給父類的構造函數傳遞參數。

所以在實際中很少單獨使用原型繼承。

二.call繼承

改變方法的this指向,同時執行方法。 在子類構造函數中父類.call(this) 可以將父類的私有變成子類的私有。

function Parent() { this.x = 100; this.y = 199;}Parent.prototype.fn = function() {} function Child() { this.d = 100; Parent.call(this); //構造函數中的this就是當前實例}var p = new Parent();var c = new Child();console.log(p) //Parent {x: 100, y: 199}console.log(c) //Child {d: 100, x: 100, y: 199}

在子類的構造函數中,改變父類的this指向,改變為子類的實例,同時運行父類方法,這樣父類中的this.x就變成了子類的實例.x ,通過這種方法就可以繼承了父類的私有屬性,且只能繼承父類的私有屬性和方法。

三.冒充對象繼承

冒充對象繼承的原理是循環遍歷父類實例,然后父類實例的私有方法全部拿過來添加給子類實例。

function Parent(){ this.x = 100;}Parent.prototype.getX = function(){ console.log(’getX’)}function Child(){ var p = new Parent(); for(var attr in p){//for in 可以遍歷到原型上的公有自定義屬性 this[attr] = p[attr] } //以下代碼是只獲得到私有方法和屬性,如果不加這個的話就可以遍歷到所有方法和屬性 /*if(e.hasOwnProperty(attr)){ this[attr] = e[attr] } e.propertyIsEnumerable()*///可枚舉屬性==> 可以拿出來一一列舉的屬性}var p = new Parent();var c = new Child();console.dir(c)

for in 可以遍歷到原型上的公有自定義屬性 ,所以他可以拿到私有和公有的屬性和方法,這個你可以遍歷私有和公有的,需要你加限制條件。但是如果不做hasOwnProperty判斷那么就是把父類的公有的和私有的都拿過來當私有的。

四.混合繼承

就是將call繼承和原型繼承集合在一起,無論是私有的還是公有的都拿過來了。但是有個問題就是子類的原型上的多了一套父類私有屬性,但是不會產生問題。因為子類的私有屬性也有一套相同的通過call繼承拿過來的。

function Parent(){ this.x=100;}Parent.prototype.getX = function(){}function Child(){ Parent.call(this);}Child.prototype = new Parent();Child.prototype.constructor = Child;var p = new Parent();var c = new Child();console.log(c)//Child {x: 100}

存在的問題:

無論在什么情況下,都會調用兩次構造函數:一次是在創建子類型原型的時候,另一次是在子類型構造函數的內部,沒錯,子類型最終會包含父類型對象的全部實例屬性,但我們不得不在調用子類構造函數時重寫這些屬性。

還有一種就是call+拷貝繼承

//混合繼承:call繼承+拷貝繼承 function extend(newEle,oldEle){ for(var attr in oldEle){ newEle[attr]=oldEle[attr]; } } function F(){ this.x=100; this.showX=function(){} } F.prototype.getX=function(){}; F.prototype.getX1=function(){}; var f1=new F; console.dir(f1) function S(){ F.call(this)//call繼承 } extend(S.prototype, F.prototype);//拷貝繼承 S.prototype.cc=function(){ } var p1=new S; console.dir(p1);

這種方式使用call繼承將父類的私有方法繼承過來,使用for in 拷貝將父類的公有屬性和方法繼承過來,比較實用。

五.中間件繼承

中間件繼承就是通過原型鏈的機制,子類的prototype.__proto__本來應該是直接指向Object.prototype。

從父類的原型上的__proto__也可以到Object.prototype,在父類.prototype上停留了下,父類.prototype就是一個中間件,所以子類可以繼承到父類的公有方法當做自己的公有方法。

function Parent(){ this.x = 100;}Parent.prototype.getX = function(){}function Child(){ }Child.prototype.__proto__ = Parent.prototype;var p = new Parent();var c = new Child()console.log(c)

六.寄生組合式繼承

   寄生式組合: call繼承+Object.create();

所謂寄生組合式繼承就是通過借用構造函數來繼承屬性,通過原型鏈的混合形式來繼承方法。

基本思路是不必為了指定子類的原型而調用父類的構造函數,我們所需要的就是父類型原型的一個副本。

本質上,就是使用寄生式繼承父類的原型,然后再將結果指定給子類的原型。

function F(){ this.x=100;}F.prototype.showX=function(){};function S(){ this.y = 200 F.call(this)//只繼承了私有的;}function inheritPrototype(subType,superType){ var prototype = Object.create(superType.prototype);//創建對象 prototype.constructor = subType;//增強對象 subType.prototype = prototype;//指定對象}inheritPrototype(S,F)var p1=new S;console.dir(p1)

1、第一步是創建父類型原型的一個副本。

2、第二步是為創建的副本增加constructor屬性,從而彌補了因為重寫原型而失去的默認的constructor屬性。

3、第三步是將創建的對象賦值給子類型的原型。

這個例子的高效率體現在他只調用了一次SuperType 構造函數,并且因此避免了在SubType.prototype上面創建不必要的、多余的屬性。與此同時原型鏈還能保持不變,所以可以正常使用instanceof 和 isPrototypeOf() ,所以寄生組合繼承是引用類型最理想的繼承方法。

七.class繼承

class 可以通過extends關鍵字實現繼承,這比 ES5 的通過修改原型鏈實現繼承,要清晰和方便很多。

class Father{ constructor(x, y) { this.x = x; this.y = y; } toString() { return ’(’ + this.x + ’, ’ + this.y + ’)’; }}class Son extends Father{ constructor(x,y,color){ super(x,y); // 調用父類的constructor(x, y) this.color = color; } toString() {console.log( super.toString()+this.color); // 調用父類的toString() }}let son = new Son(3,4,’red’);son.toString();//結果為(3,4)red

上面代碼定義了一個Son類,該類通過extends關鍵字,繼承了Father類的所有屬性和方法。

上面代碼中,constructor方法和toString方法之中,都出現了super關鍵字,它在這里表示父類的構造函數,用來新建父類的this對象。

子類必須在constructor方法中調用super方法,否則新建實例時會報錯。這是因為子類自己的this對象,必須先通過父類的構造函數完成塑造,得到與父類同樣的實例屬性和方法,然后再對其進行加工,加上子類自己的實例屬性和方法。如果不調用super方法,子類就得不到this對象。

以上就是JavaScript 常見的繼承方式匯總的詳細內容,更多關于JavaScript 繼承方式的資料請關注好吧啦網其它相關文章!

標簽: JavaScript
相關文章:
主站蜘蛛池模板: 橡胶接头_橡胶软接头_套管伸缩器_管道伸缩器厂家-巩义市远大供水材料有限公司 | 济南轻型钢结构/济南铁艺护栏/济南铁艺大门-济南燕翔铁艺制品有限公司 | 压接机|高精度压接机|手动压接机|昆明可耐特科技有限公司[官网] 胶泥瓷砖胶,轻质粉刷石膏,嵌缝石膏厂家,腻子粉批发,永康家德兴,永康市家德兴建材厂 | 减速机三参数组合探头|TSM803|壁挂式氧化锆分析仪探头-安徽鹏宸电气有限公司 | 烟台游艇培训,威海游艇培训-烟台市邮轮游艇行业协会 | 金属软管_不锈钢金属软管_巩义市润达管道设备制造有限公司 | 智能化的检漏仪_气密性测试仪_流量测试仪_流阻阻力测试仪_呼吸管快速检漏仪_连接器防水测试仪_车载镜头测试仪_奥图自动化科技 | 在线浊度仪_悬浮物污泥浓度计_超声波泥位计_污泥界面仪_泥水界面仪-无锡蓝拓仪表科技有限公司 | 艾默生变频器,艾默生ct,变频器,ct驱动器,广州艾默生变频器,供水专用变频器,风机变频器,电梯变频器,艾默生变频器代理-广州市盟雄贸易有限公司官方网站-艾默生变频器应用解决方案服务商 | 微水泥_硅藻泥_艺术涂料_艺术漆_艺术漆加盟-青岛泥之韵环保壁材 武汉EPS线条_EPS装饰线条_EPS构件_湖北博欧EPS线条厂家 | 灌木树苗-绿化苗木-常绿乔木-价格/批发/基地 - 四川成都途美园林 | 数显水浴恒温振荡器-分液漏斗萃取振荡器-常州市凯航仪器有限公司 | 外贮压-柜式-悬挂式-七氟丙烷-灭火器-灭火系统-药剂-价格-厂家-IG541-混合气体-贮压-非贮压-超细干粉-自动-灭火装置-气体灭火设备-探火管灭火厂家-东莞汇建消防科技有限公司 | 重庆网站建设,重庆网站设计,重庆网站制作,重庆seo,重庆做网站,重庆seo,重庆公众号运营,重庆小程序开发 | 飞象网 - 通信人每天必上的网站| 皮带式输送机械|链板式输送机|不锈钢输送机|网带输送机械设备——青岛鸿儒机械有限公司 | 山东聚盛新型材料有限公司-纳米防腐隔热彩铝板和纳米防腐隔热板以及钛锡板、PVDF氟膜板供应商 | 披萨石_披萨盘_电器家电隔热绵加工定制_佛山市南海区西樵南方综合保温材料厂 | 浙江华锤电器有限公司_地磅称重设备_防作弊地磅_浙江地磅售后维修_无人值守扫码过磅系统_浙江源头地磅厂家_浙江工厂直营地磅 | 防火卷帘门价格-聊城一维工贸特级防火卷帘门厂家▲ | 拉曼光谱仪_便携式|激光|显微共焦拉曼光谱仪-北京卓立汉光仪器有限公司 | 播音主持培训-中影人教育播音主持学苑「官网」-中国艺考界的贵族学校 | 碳化硅,氮化硅,冰晶石,绢云母,氟化铝,白刚玉,棕刚玉,石墨,铝粉,铁粉,金属硅粉,金属铝粉,氧化铝粉,硅微粉,蓝晶石,红柱石,莫来石,粉煤灰,三聚磷酸钠,六偏磷酸钠,硫酸镁-皓泉新材料 | 铝箔-铝板-花纹铝板-铝型材-铝棒管-上海百亚金属材料有限公司 | 广州迈驰新GMP兽药包装机首页_药品包装机_中药散剂包装机 | 北京征地律师,征地拆迁律师,专业拆迁律师,北京拆迁律师,征地纠纷律师,征地诉讼律师,征地拆迁补偿,拆迁律师 - 北京凯诺律师事务所 | 青岛侦探_青岛侦探事务所_青岛劝退小三_青岛婚外情取证-青岛王军侦探事务所 | 苏州同创电子有限公司 - 四探针测试仪源头厂家 | 重庆中专|职高|技校招生-重庆中专招生网 | 成都竞价托管_抖音代运营_网站建设_成都SEM外包-成都智网创联网络科技有限公司 | 欧景装饰设计工程有限公司-无锡欧景装饰官网 | ★店家乐|服装销售管理软件|服装店收银系统|内衣店鞋店进销存软件|连锁店管理软件|收银软件手机版|会员管理系统-手机版,云版,App | 可程式恒温恒湿试验箱|恒温恒湿箱|恒温恒湿试验箱|恒温恒湿老化试验箱|高低温试验箱价格报价-广东德瑞检测设备有限公司 | 天津仓库出租网-天津电商仓库-天津云仓一件代发-【博程云仓】 | Magnescale探规,Magnescale磁栅尺,Magnescale传感器,Magnescale测厚仪,Mitutoyo光栅尺,笔式位移传感器-苏州连达精密量仪有限公司 | 卫生纸复卷机|抽纸机|卫生纸加工设备|做卫生纸机器|小型卫生纸加工需要什么设备|卫生纸机器设备多少钱一台|许昌恒源纸品机械有限公司 | 广东风淋室_广东风淋室厂家_广东风淋室价格_广州开源_传递窗_FFU-广州开源净化科技有限公司 | 冷热冲击试验箱_温度冲击试验箱价格_冷热冲击箱排名_林频厂家 | 电解抛光加工_不锈钢电解抛光_常州安谱金属制品有限公司 | 济南轻型钢结构/济南铁艺护栏/济南铁艺大门-济南燕翔铁艺制品有限公司 | 亮化工程,亮化设计,城市亮化工程,亮化资质合作,长沙亮化照明,杰奥思【官网】 |