日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

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

全面解析js中的原型,原型對象,原型鏈

瀏覽:233日期:2024-04-06 16:45:12
理解原型

我們創建的每一個函數都有一個prototype(原型)屬性,這個屬性是一個指針,指向一個對象,而這個對象的用途是包含可以由特定類型的所有實例共享的屬性和方法。看如下例子:

function Person(){}Person.prototype.name = ’ccc’Person.prototype.age = 18Person.prototype.sayName = function (){ console.log(this.name);}var person1 = new Person()person1.sayName() // --> cccvar person2 = new Person()person2.sayName() // --> cccconsole.log(person1.sayName === person2.sayName) // --> true理解原型對象

根據上面代碼,看下圖:

全面解析js中的原型,原型對象,原型鏈

需要理解三點:

我們只要創建了一個新的函數,就會根據一組特定的規則為該函數創建一個prototype屬性,指向函數的原型對象。即Person(構造函數)有一個prototype指針,指向Person.prototype 默認情況下,每個原型對象上都會創建一個constructor(構造函數)屬性,這個屬性是一個指向prototype屬性所在函數的指針 每個實例的內部都有一個指針(內部屬性) ,指向構造函數的原型對象。即 person1 和person2 身上都有一個內部屬性__proto__(在ECMAscript中管這個指針叫[[prototype]],雖然在腳本中沒有標準的方式訪問[[prototype]],但是firefox,ie,chrome都支持一個屬性叫__proto__) 指向Person.prototype

注意:person1 和person2 實例與構造函數之間沒有直接的關系。

在之前我們提到,所有實現中無法訪問到[[prototype]],那我們如何知道實例和原型對象之間是否存在關系呢?這里可以通過兩個方法來判斷:

原型對線上的方法:isPrototypeOf(),如:console.log(Person.prototype.isPrototypeOf(person1)) // --> true ECMAscript5中新增的一個方法:Object.getPrototypeOf(),這個方法返回[[prototype]]的值。如:console.log(Object.getPrototypeOf(person1) === Person.prototype) // --> true 實例屬性與原型屬性的關系

前面我們提到過,原型最初只包含constructor屬性,而該屬性也是共享的,因此可以通過對象實例訪問。雖然可以通過對象實例訪問保存在原型中的值,但卻不能通過對象實例重寫原型中的值。如果我們在實例中添加了一個屬性,而改屬性與實例原型中的一個屬性同名,那就會在實例上創建該屬性并屏蔽原型中的那個屬性。如下:

function Person() {}Person.prototype.name = 'ccc';Person.prototype.age = 18;Person.prototype.sayName = function() { console.log(this.name);};var person1 = new Person();var person2 = new Person();person1.name = ’www’ // 在person1中添加一個name屬性person1.sayName() // --> ’www’————’來自實例’person2.sayName() // --> ’ccc’————’來自原型’console.log(person1.hasOwnProperty(’name’)) // --> trueconsole.log(person2.hasOwnProperty(’name’)) // --> falsedelete person1.name // --> 刪除person1中新添加的name屬性person1.sayName() // -->’ccc’————’來自原型’

我們如何判斷一個屬性,到底是實例上的屬性還是原型上的屬性?這里可以通過hasOwnProperty()方法來檢測一個屬性是存在于實例中還是存在于原型中。(此方法繼承于Object)

下圖詳細分析了上面例子在不同情況下的實現與原型的關系:(省略了Person構造函數的的關系)

全面解析js中的原型,原型對象,原型鏈

更簡單的原型語法

我們不可能總像之前的例子一樣,沒添加一個屬性和方法就要敲一遍,Person.prototype。為了減少不必要的輸入,更常見的方法是像下面這樣:

function Person(){}Person.prototype ={ name: ’ccc’, age: 18, sayName: function () { console.log(this.name) }}

在上面代碼中,我們將Person.prototype設置為等于一個以對象字面量形式創建的新對象。最終結果相同,但有一個例外,constructor屬性不再指向Person了。前面我們介紹過,每創建一個函數,就會同時創建它的prototype對象,這個對象也會自動獲得constructor屬性。但是在我們使用的新語法中,本質上完全重寫了默認的prototype對象,因此constructor屬性也就變成了新對象的constructor屬性(指向Object構造函數),不再指向Person函數了。此時,盡管instanceof操作符還能返回正確的結果,但通過constructor已經無法確定對象的類型了。如下:

var person1 = new Person()console.log(person1 instanceof Object) // --> trueconsole.log(person1 instanceof Person) // --> trueconsole.log(person1.constructor === Person) // --> falseconsole.log(person1.constructor === Object) // --> true

這里用instanceof操作符測試Object和Person仍然返回true,constructor屬性則等于Object,不等于Person了,如果constructor真的很重要可以像下面這樣寫:

function Person(){}Person.prototype ={ constructor: Person, // --> 重設 name: ’ccc’, age: 18, sayName: function () { console.log(this.name) }}

但是這會引起一個新問題,用上述方式重置constructor屬性會導致它的[[Enumerable]]特性被設置為true。而默認情況下,原生的constructor屬性是不可枚舉的。因此如果你要使用兼容ECMAscript5的JavaScript引擎,可以試一試Object.defineProperty()。

function Person(){}Person.constructor = { name: ’ccc’, age: 18, sayName: function(){ console.log(this.name) }}// 重設構造函數,只適用于ECMAscript5兼容的瀏覽器Object.defineProperty(Person.constructor, 'constructor', { enumerable: false, value: Person})原型的動態性

由于原型中查找值的過程是一次搜索,因此我們對原型對象所做的任何修改都能立即從實例上反映出來。比如:

function Person(){}var person1 = new Person()Person.prototype.sayHi= function(){ console.log(’hi’)}person1.sayHi()

上述代碼我們先創建了一個Person實例,并將其保存在person1中,然后在Person.prototype中添加了sayHi()方法。即使person1是添加新方法之前創建的,但它仍然可以訪問這個方法。原因是實例與原型之間的松散的連接關系。盡管可以隨時為原型添加屬性和方法,并立即能夠在實例中反映出來。但是如果重寫整個原型對象,那么情況就不一樣了。看如下代碼:

function Person(){}var person1 = new Person()Person.prototype = { name: ’ccc’, age: 18, sayName: function(){ console.log(this.name) }}person1.sayName() // --> error

看下圖分析:

全面解析js中的原型,原型對象,原型鏈

調用構造函數時為實例添加了一個指向最初原型的[[prototype]]指針,而把原型修改為另外一個對象就等于切斷了構造函數與最初原型之間的聯系。請記住:實例中的指針僅指向原型,而不指向構造函數。

理解原型鏈

原型鏈是實現繼承的主要方法。其基本思想是讓一個引用類型繼承另一個引用類型的屬性和方法。在理解原型鏈之前,我們首先得捋一下,原型,原型對象,實例之間的關系:每一個構造函數都有一個原型對象,原型對象都包含一個指向構造函數的指針,而實例都包含一個指向原型對象的內部指針。假如我們讓原型對象等于另一個類型的實例會怎么樣?顯然,這個原型對象將會包含一個指向另一個原型的指針。先看代碼在看圖:

function SuperType(){ this.property = true}SuperType.prototype.getSuperValue = function(){ return this.property}function SubType(){ this.subProperty = false}// 繼承了SuperTypeSubType.prototype = new SuperType()SubType.prototype.getSubValue = function (){ return this.subProperty}var instance = new SubType()console.log(instance.getSuperValue()) // --> true

上述代碼定義了兩個類型:SuperType和SubType。每個類型分別有一個屬性和一個方法。

全面解析js中的原型,原型對象,原型鏈

分析上圖:instance 指向SubType原型,SubType的原型又指向SuperType的原型。getSuperValue()方法仍然還在SuperType.prototype中,但property則位于SubType.prototype中。這是因為property是一個實例屬性,而getSuperValue()則是一個原型方法。既然SubType.prototype現在是SuperType的實例,那么property當然就位于該實例中。此外要注意,instance.constructor現在指向的是SuperType,這是因為原來的SubType.prototype中的constructor被重寫了的緣故。為什么會返回true?分析:調用instance.getSuperValue()方法會經歷三個搜索步驟:

搜索實例搜索SubType.prototype搜索SuperType.prototype,直到這里才找到方法。在找不到屬性或方法的情況下,搜索過程總是要一環一環地前行到原型鏈末端才會停下來。

別忘記默認的原型

要知道,所有的引用類型默認都繼承了Object,而這個繼承也是通過原型鏈實現的。所有函數的默認原型都是Object的實例,因此默認原型都會包含一個內部指針,指向Object.prototype,這也正是所有自定義類型都會有toString(),valueOf()方法的原因。所以完整的原型鏈應該如下:看下圖,subType的內部:

全面解析js中的原型,原型對象,原型鏈

詳細圖解:

全面解析js中的原型,原型對象,原型鏈

總之一句話,SubType繼承了SuperType,而SuperType繼承了Object。當調用instanct.toString()的時候,實際上調用的是保存在Object.prototype中的那個方法。

確定原型和實例的關系

當一個原型鏈很長的時候,想要確定原型和實例的關系,總共有兩種方法:

使用instanceof 操作符,只要用這個操作符來測試實例與原型鏈中出現過的構造函數,結果就會返回true。

console.log(instance instanceof Object) // --> trueconsole.log(instance instanceof SuperType) // --> trueconsole.log(instance instanceof SubType) // --> true

使用isPrototypeOf()方法,跟instanctof判別方法類似,只要原型鏈中出現過的原型,都會返回true。

console.log(Object.prototype.isPrototypeOf(instance)) // --> trueconsole.log(SuperType.prototype.isPrototypeOf(instance)) // --> trueconsole.log(SubType.prototype.isPrototypeOf(instance)) // --> true謹慎地定義方法

子類型有時候需要覆蓋超類型中的某個方法,或者需要添加超類型中不存在的某個方法。但不管怎樣,給原型添加方法的代碼一定要放在替換原型的語句之后。如下:

function SuperType(){ this.property = true;}SuperType.prototype.getSuperValue = function(){ return this.property}function SubType(){ this.subProperty = false;}// 繼承了 SuperTypeSubType.prototype = new SuperType()// 添加新方法SubType.prototype.getSubValue = function(){ return this.subProperty}// 重寫超類型中的方法SubType.prototype.getSuperValue = function(){ return false}var instance = new SubType()console.log(instance.getSuperValue()) // --> falsevar instanceSuper = new SuperType()console.log(instanceSuper.getSuperValue()) // -> true

上述代碼中,第一個方法getSubValue()被添加到了SubType中。第二個方法getSuperValue()是原型鏈中已經存在的一個方法,但重寫這個方法將會屏蔽原來的那個方法。即當通過SubType的實例調用getSuperValue()時,調用的就是這個重新定義的方法,但通過SuperType的實例調用getSuperValue()時,還會繼續調用原來的那個方法。還有一點,在通過原型鏈實現繼承的時候,不能使用對象自變量創建原型方法,因為這樣會重寫原型鏈,導致原型鏈被切斷。

原型鏈的問題

通過原型來實現繼承時,原型實際上會變成另一個類型的實例,于是,原先的實例屬性就變成了現在的原型屬性了,這就會導致屬性被共享。看如下代碼:

function SuperType(){ this.colors = [’white’, ’blue’]}function SubType(){}// 繼承了SuperTypeSubType.prototype = new SuperType()var instance1 = new SubType()instance1.colors.push(’red’)var instance2 = new SubType()console.log(instance1.colors) // -->['white', 'blue', 'red']console.log(instance2.colors) // -->['white', 'blue', 'red']

在創建子類型的實例時,不能向超類型的構造函數中傳遞參數。實際上,應該是沒有辦法在不影響所有對象實例的情況下,給超類型的構造函數傳遞參數。因此,在實踐中很少會單獨使用原型鏈。

以上就是圖解js中的原型,原型對象,原型鏈的詳細內容,更多關于js中的原型,原型對象,原型鏈的資料請關注好吧啦網其它相關文章!

標簽: JavaScript
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
欧美午夜精彩| 国产亚洲激情| 亚洲永久精品唐人导航网址| 欧美日韩国产在线观看网站 | 欧美日韩一二三四| 中文一区一区三区高中清不卡免费| 国产麻豆一区二区三区| 欧美日本不卡| 久久精品999| 欧美激情精品| 六月婷婷综合| 欧美日韩国产探花| 在线视频亚洲欧美中文| 日韩av网站在线观看| 国产欧美日韩视频在线| 精品视频91| 国产在线观看www| 欧美+日本+国产+在线a∨观看| 亚洲小说欧美另类婷婷| 亚洲黄页一区| 日韩综合一区二区| 国产乱码精品一区二区三区四区| 国产精品nxnn| 国产精品xx| 欧美~级网站不卡| 青青在线精品| 久久精品国产68国产精品亚洲| 免费看的黄色欧美网站| 欧美亚洲福利| 欧美丝袜一区| 97精品国产99久久久久久免费| 久久三级毛片| 石原莉奈在线亚洲二区| 欧美成人aaa| 最新国产精品久久久| 日韩a一区二区| 亚洲a成人v| 欧美日韩国产传媒| 国产精品一级在线观看| 欧美亚洲国产激情| 风间由美中文字幕在线看视频国产欧美| 亚洲午夜精品久久久久久app| 国产精品久久久一区二区| 久久久久国产精品一区二区| 国产欧美日韩亚洲一区二区三区| 免费久久99精品国产自在现线| 精品入口麻豆88视频| 日韩精品电影一区亚洲| 午夜电影亚洲| 欧美日韩精品免费观看视欧美高清免费大片| 亚洲图片久久| 国产亚洲毛片在线| 亚洲一级少妇| 国产aⅴ精品一区二区四区| 亚洲黄色影院| 蜜臀久久99精品久久一区二区| 狠狠久久伊人中文字幕| 国产精品一区三区在线观看| 免费观看在线综合色| 国产毛片一区| 欧美综合国产| 美女网站久久| 蜜桃视频一区二区| 亚洲丝袜啪啪| 日韩av影院| 日韩精品亚洲aⅴ在线影院| 丝瓜av网站精品一区二区| 99国产成+人+综合+亚洲欧美| 黄色亚洲在线| 日本韩国欧美超级黄在线观看| 神马午夜在线视频| 国产91精品对白在线播放| 国产精品av久久久久久麻豆网| 欧美成人精品| 丝袜美腿一区二区三区| 日韩精品欧美大片| 欧美片第1页综合| 激情中国色综合| 久久高清精品| 在线观看一区| 麻豆成人综合网| 快播电影网址老女人久久| 久久中文字幕av| 男人的天堂亚洲一区| 欧美特黄视频| 日韩精品欧美大片| 精品久久精品| 欧美日韩国产综合网| 日韩av一级片| 欧美成人基地 | 国产精品99久久精品| 999国产精品永久免费视频app| 美日韩精品视频| 国产va免费精品观看精品视频| 国产成人精品亚洲日本在线观看| 国产美女一区| 成人一二三区| 日本精品久久| 欧美日韩视频一区二区三区| 久久99蜜桃| 99在线|亚洲一区二区| 国产精品亚洲欧美一级在线| 激情91久久| 波多野结衣久久精品| 日本午夜免费一区二区| 欧美日韩国产一区精品一区| 久久三级中文| 日本色综合中文字幕| 亚洲一区成人| 国产福利一区二区精品秒拍| 99在线精品免费视频九九视| 日韩av在线播放网址| 国产精品二区影院| 色8久久久久| 免费在线成人网| 午夜在线精品| 91精品二区| 色婷婷久久久| 亚洲va中文在线播放免费| 精品国产乱码久久久久久樱花| 日韩精品三级| 欧美日韩视频免费看| 日韩成人精品一区二区三区| 久久午夜影视| 免费av一区| 在线一区欧美| 欧美专区在线| 三级一区在线视频先锋| 亚洲综合国产| 中文字幕av亚洲精品一部二部 | 欧美国产不卡| 精品三级在线观看视频| 免费一级欧美片在线观看网站| 91精品视频一区二区| 国产一级成人av| 国产精品红桃| 亚洲伦乱视频| 亚洲播播91| 亚洲激情不卡| 亚洲综合小说| 国产日韩欧美| 国产一区二区三区久久 | 久久av影院| av资源新版天堂在线| 91精品久久久久久久久久不卡| 99精品综合| 午夜在线播放视频欧美| 日韩va亚洲va欧美va久久| 日韩动漫一区| 色乱码一区二区三区网站| 天堂а√在线最新版中文在线| 日韩中文在线电影| 性一交一乱一区二区洋洋av| 日韩av一二三| 麻豆精品蜜桃| 免费精品视频在线| 欧美精品不卡| 国产主播一区| 国产日韩中文在线中文字幕| 精品久久一区| 日韩午夜精品| 国产成人免费精品| 午夜精品免费| 日韩精品一区二区三区免费视频 | 婷婷综合亚洲| 欧美精品不卡| 亚洲女同中文字幕| 奇米亚洲欧美| 99久久久国产精品美女| 国产伦理久久久久久妇女| 欧美影院三区| 日本在线观看不卡视频| 日韩成人精品一区二区| 久久午夜影视| 国精品产品一区| 视频在线在亚洲| 你懂的国产精品| 在线看片一区| 亚洲激情二区| а√在线中文在线新版| 国产精品中文字幕亚洲欧美| 日韩中文欧美在线| 久久人人97超碰国产公开结果| 国产亚洲欧美日韩精品一区二区三区| 日本不卡高清| 欧美91在线|欧美| 国产亚洲字幕| 精品国产欧美日韩一区二区三区| 黑森林国产精品av| 欧美日韩伊人| 亚洲欧美日韩国产综合精品二区| 国产无遮挡裸体免费久久| 亚洲欧洲美洲国产香蕉| 美女久久99| 视频在线在亚洲| 91免费精品国偷自产在线在线| 日韩国产在线观看| 国产精品美女久久久久久不卡| 国产亚洲精品自拍| 亚洲欧美一区在线|