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

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

JS原形與原型鏈深入詳解

瀏覽:97日期:2024-05-09 11:06:14

本文實例講述了JS原形與原型鏈。分享給大家供大家參考,具體如下:

前言

在JS中,我們經常會遇到原型。字面上的意思會讓我們認為,是某個對象的原型,可用來繼承。但是其實這樣的理解是片面的,下面通過本文來了解原型與原型鏈的細節,再順便談談繼承的幾種方式。

原型

在講到原型之前,我們先來回顧一下JS中的對象。在JS中,萬物皆對象,就像字符串、數值、布爾、數組等。ECMA-262把對象定義為:無序屬性的集合,其屬性可包含基本值、對象或函數。對象是擁有屬性和方法的數據,為了描述這些事物,便有了原型的概念。

無論何時,只要創建了一個新函數,就會根據一組特定的規則為該函數創建一個prototype屬性,這個屬性指向該函數的原型對象。所有原型對象都會獲得一個constructor屬性,這個屬性包含一個指向prototype屬性所在函數的指針。

這段話摘自《JS高級程序設計》,很好理解,以創建實例的代碼為例。

function Person(name, age) { this.name = name; this.age = age; this.sayName = function() { alert(this.name); };}const person1 = new Person('gali', 18);const person2 = new Person('pig', 20);

JS原形與原型鏈深入詳解

上面例子中的person1跟person2都是構造函數Person()的實例,Person.prototype指向了Person函數的原型對象,而Person.prototype.constructor又指向Person。Person的每一個實例,都含有一個內部屬性__proto__,指向Person.prototype,就像上圖所示,因此就有下面的關系。

console.log(Person.prototype.constructor === Person); // trueconsole.log(person1.__proto__ === Person.prototype); // trueconsole.log(person2.__proto__ === Person.prototype); // true繼承

JS是基于原型的語言,跟基于類的面向對象語言有所不同,JS中并沒有類這個概念,有的是原型對象這個概念,原型對象作為一個模板,新對象可從原型對象中獲得屬性。那么JS具體是怎樣繼承的呢?

在講到繼承這個話題之前,我們先來理解原型鏈這個概念。

原型鏈

構造函數,原型和實例的關系已經很清楚了。每個構造函數都有一個原型對象,原型對象都包含一個指向構造函數的指針,而實例對象都包含一個指向與原型對象的指針。這樣的關系非常好理解,但是如果我們想讓原型對象等于另一個類型的實例對象呢?那么就會衍生出相同的關系,此時的原型對象就會含有一個指向另一個原型對象的指針,而另一個原型對象會含有一個指向另一個構造函數的指針。如果另一個原型對象又是另一個類型的實例對象呢?這樣就構成了原型鏈。文字可能有點難理解,下面用代碼舉例。

function SuperType() { this.name = '張三';}SuperType.prototype.getSuperName = function() { return this.name;};function SubType() { this.subname = '李四';}SubType.prototype = new SuperType();SubType.prototype.getSubName = function() { return this.subname;};const instance = new SubType();console.log(instance.getSuperName()); // 張三

上述例子中,SubType的原型對象作為SuperType構造函數的實例對象,此時,SubType的原型對象就會有一個__proto__屬性指向SuperType的原型對象,instance作為SubType的實例對象,必然能共享SubType的原型對象的屬性,又因為SubType的原型對象又指向SuperType原型對象的屬性,因此可得,instance繼承了SuperType原型的所有屬性。

我們都知道,所有函數的默認原型都是Object的實例,所以也能得出,SuperType的默認原型必然有一個__proto__指向Object.prototype。

圖中由__proto__屬性組成的鏈子,就是原型鏈,原型鏈的終點就是null

JS原形與原型鏈深入詳解

上圖可很清晰的看出原型鏈的結構,這不禁讓我想到JS的一個運算符instanceof,instanceof可用來判斷一個實例對象是否屬于一個構造函數。

A instanceof B; // true

實現原理其實就是在A的原型鏈上尋找是否有原型等于B.prototype,如果一直找到A原型鏈的頂端null,仍然找不到原型等于B.prototype,那么就可返回false。下面手寫一個instanceof,這個也是很多大廠常用的手寫面試題。

function Instance(left, right) { left = left.__proto__; right = right.prototype; while (true) { if (left === null) return false; if (left === right) return true; // 繼續在left的原型鏈向上找 left = left.__propo__; }}原型鏈繼承

上面例子中,instance繼承了SuperType原型的屬性,其繼承的原理其實就是通過原型鏈實現的。原型鏈很強大,可用來實現繼承。可是單純的原型鏈繼承也是有問題存在的。

實例屬性變成原型屬性,影響其他實例 創建子類型的實例時,不能向超類型的構造函數傳遞參數

function SuperType() { this.colorArr = ['red', 'blue', 'green'];}function SubType() {}SubType.prototype = new SuperType();const instance1 = new SubType();instance1.colorArr.push('black');console.log(instance1.colorArr); // ['red', 'blue', 'green', 'black']const instance2 = new SubType();console.log(instance2.colorArr); // ['red', 'blue', 'green', 'black']

當SubType的原型作為SuperType的實例時,此時SubType的實例對象通過原型鏈繼承到colorArr屬性,當修改了其中一個實例對象從原型鏈中繼承到的原型屬性時,便會影響到其他實例。對instance1.colorArr的修改,在instance2.colorArr便能體現出來。

組合繼承

組合繼承指的是組合原型鏈和構造函數的技術,通過原型鏈實現對原型屬性和方法的繼承,而通過借用構造函數實現對實例屬性的繼承。

function SuperType(name) { this.name = name; this.colors = ['red', 'blue', 'green'];}SuperType.prototype.sayName = function() { console.log(this.name);};function SubType(name, age) { // 繼承屬性,借用構造函數實現對實例屬性的繼承 SuperType.call(this, name); this.age = age;}// 繼承原型屬性及方法SubType.prototype = new SuperType();SubType.prototype.constructor = SubType;SubType.prototype.sayAge = function() { console.log(this.age);};const instance1 = new SubType('gali', 18);instance1.colors.push('black');console.log(instance1.colors); // ['red', 'blue', 'green', 'black']instance1.sayName(); // galiinstance1.sayAge(); // 18const instance2 = new SubType('pig', 20);console.log(instance2.colors); // ['red', 'blue', 'green']instance2.sayName(); // piginstance2.sayAge(); // 20

上述例子中,借用構造函數繼承實例屬性,通過原型繼承原型屬性與方法。這樣就可讓不同的實例分別擁有自己的屬性,又可共享相同的方法。而不會像原型繼承那樣,對實例屬性的修改影響到了其他實例。組合繼承是JS最常用的繼承方式。

寄生組合式繼承

雖然說組合繼承是最常用的繼承方式,但是有沒有發現,就上面的例子中,組合繼承中調用了2次SuperType函數。回憶一下,在第一次調用SubType時。

SubType.prototype = new SuperType();

這里調用完之后,SubType.prototype會從SuperType繼承到2個屬性:name和colors。這2個屬性存在SubType的原型中。而在第二次調用時,就是在創造實例對象時,調用了SubType構造函數,也就會再調用一次SuperType構造函數。

SuperType.call(this, name);

第二次調用之后,便會在新的實例對象上創建了實例屬性:name和colors。也就是說,這個時候,實例對象跟原型對象擁有2個同名屬性。這樣實在是浪費,效率又低。

為了解決這個問題,引入了寄生組合繼承方式。重點就在于,不需要為了定義SubType的原型而去調用SuperType構造函數,此時只需要SuperType原型的一個副本,并將其賦值給SubType的原型即可。

function InheritPrototype(subType, superType) { // 創建超類型原型的一個副本 const prototype = Object(superType.prototype); // 添加constructor屬性,因為重寫原型會失去constructor屬性 prototype.constructor = subType; subType.prototype = prototype;}

將組合繼承中的:

SubType.prototype = new SuperType();SubType.prototype.constructor = SubType;

替換成:

InheritPrototype(SubType, SuperType);

寄生組合繼承的優點在于,只需要調用一次SuperType構造函數。避免了在SubType的原型上創建多余的不必要的屬性。

總結

溫故而知新,再次看回《JS高級程序設計》這本書的原型與原型鏈部分,發現很多以前忽略掉的知識點。而這次回看這個知識點,并輸出了一篇文章,對我來說受益匪淺。寫文章往往不是為了寫出怎樣的文章,其實中間學習的過程才是最享受的。

感興趣的朋友可以使用在線HTML/CSS/JavaScript代碼運行工具:http://tools.jb51.net/code/HtmlJsRun測試上述代碼運行效果。

更多關于JavaScript相關內容感興趣的讀者可查看本站專題:《javascript面向對象入門教程》、《JavaScript錯誤與調試技巧總結》、《JavaScript數據結構與算法技巧總結》、《JavaScript遍歷算法與技巧總結》及《JavaScript數學運算用法總結》

希望本文所述對大家JavaScript程序設計有所幫助。

標簽: JavaScript
相關文章:
主站蜘蛛池模板: ORP控制器_ORP电极价格-上优泰百科 | 继电器模组-IO端子台-plc连接线-省配线模组厂家-世麦德 | 高压油管,液压接头,液压附件-烟台市正诚液压附件 | PAS糖原染色-CBA流式多因子-明胶酶谱MMP-上海研谨生物科技有限公司 | 管家婆-管家婆软件-管家婆辉煌-管家婆进销存-管家婆工贸ERP | 无硅导热垫片-碳纤维导热垫片-导热相变材料厂家-东莞市盛元新材料科技有限公司 | 智成电子深圳tdk一级代理-提供TDK电容电感贴片蜂鸣器磁芯lambda电源代理经销,TDK代理商有哪些TDK一级代理商排名查询。-深圳tdk一级代理 | 新能源汽车电池软连接,铜铝复合膜柔性连接,电力母排-容发智能科技(无锡)有限公司 | 开业庆典_舞龙舞狮_乔迁奠基仪式_开工仪式-神挚龙狮鼓乐文化传媒 | 贝壳粉涂料-内墙腻子-外墙腻子-山东巨野七彩贝壳漆业中心 | KBX-220倾斜开关|KBW-220P/L跑偏开关|拉绳开关|DHJY-I隔爆打滑开关|溜槽堵塞开关|欠速开关|声光报警器-山东卓信有限公司 | 烟气换热器_GGH烟气换热器_空气预热器_高温气气换热器-青岛康景辉 | 加盟店-品牌招商加盟-创业项目商机平台 | 理化生实验室设备,吊装实验室设备,顶装实验室设备,实验室成套设备厂家,校园功能室设备,智慧书法教室方案 - 东莞市惠森教学设备有限公司 | 电镀电源整流器_高频电解电源_单脉双脉冲电源 - 东阳市旭东电子科技 | 伺服电机_直流伺服_交流伺服_DD马达_拓达官方网站 | 整车VOC采样环境舱-甲醛VOC预处理舱-多舱法VOC检测环境仓-上海科绿特科技仪器有限公司 | 厂房出租_厂房出售_产业园区招商_工业地产 - 中工招商网 | 深圳美安可自动化设备有限公司,喷码机,定制喷码机,二维码喷码机,深圳喷码机,纸箱喷码机,东莞喷码机 UV喷码机,日期喷码机,鸡蛋喷码机,管芯喷码机,管内壁喷码机,喷码机厂家 | 南京试剂|化学试剂|分析试剂|实验试剂|cas号查询-专业60年试剂销售企业 | 高压互感器,电流互感器,电压互感器-上海鄂互电气科技有限公司 | 软瓷_柔性面砖_软瓷砖_柔性石材_MCM软瓷厂家_湖北博悦佳软瓷 | 钢格栅板_钢格板网_格栅板-做专业的热镀锌钢格栅板厂家-安平县迎瑞丝网制造有限公司 | 北京易通慧公司从事北京网站优化,北京网络推广、网站建设一站式服务商-北京网站优化公司 | 欧洲MV日韩MV国产_人妻无码一区二区三区免费_少妇被 到高潮喷出白浆av_精品少妇自慰到喷水AV网站 | 数码管_LED贴片灯_LED数码管厂家-无锡市冠卓电子科技有限公司 | 滤芯,过滤器,滤油机,贺德克滤芯,精密滤芯_新乡市宇清流体净化技术有限公司 | 微型气泵-真空-蠕动-水泵-厂家-深圳市品亚科技有限公司 | 标准件-非标紧固件-不锈钢螺栓-非标不锈钢螺丝-非标螺母厂家-三角牙锁紧自攻-南京宝宇标准件有限公司 | 胶原检测试剂盒,弹性蛋白检测试剂盒,类克ELISA试剂盒,阿达木单抗ELISA试剂盒-北京群晓科苑生物技术有限公司 | 台湾HIWIN上银直线模组|导轨滑块|TBI滚珠丝杆丝杠-深圳汉工 | 常州翔天实验仪器厂-恒温振荡器-台式恒温振荡器-微量血液离心机 恒温恒湿箱(药品/保健品/食品/半导体/细菌)-兰贝石(北京)科技有限公司 | 卷筒电缆-拖链电缆-特种柔性扁平电缆定制厂家「上海缆胜」 | 河北中仪伟创试验仪器有限公司是专业生产沥青,土工,水泥,混凝土等试验仪器的厂家,咨询电话:13373070969 | 曙光腾达官网-天津脚手架租赁-木板架出租-移动门式脚手架租赁「免费搭设」 | 超声波成孔成槽质量检测仪-压浆机-桥梁预应力智能张拉设备-上海硕冠检测设备有限公司 | 亚克力制品定制,上海嘉定有机玻璃加工制作生产厂家—官网 | 东莞办公家具厂家直销-美鑫【免费3D效果图】全国办公桌/会议桌定制 | 英思科GTD-3000EX(美国英思科气体检测仪MX4MX6)百科-北京嘉华众信科技有限公司 | 螺杆真空泵_耐腐蚀螺杆真空泵_水环真空泵_真空机组_烟台真空泵-烟台斯凯威真空 | SRRC认证|CCC认证|CTA申请_IMEI|MAC地址注册-英利检测 |