成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

JavaScript中原型和原型對(duì)象是什么-創(chuàng)新互聯(lián)

JavaScript中原型和原型對(duì)象是什么?很多新手對(duì)此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。

站在用戶的角度思考問題,與客戶深入溝通,找到吳橋網(wǎng)站設(shè)計(jì)與吳橋網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個(gè)性化、用戶體驗(yàn)好的作品,建站類型包括:網(wǎng)站設(shè)計(jì)制作、網(wǎng)站制作、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、國際域名空間、虛擬主機(jī)、企業(yè)郵箱。業(yè)務(wù)覆蓋吳橋地區(qū)。

理解原型

我們創(chuàng)建的每一個(gè)函數(shù)都有一個(gè)prototype(原型)屬性,這個(gè)屬性是一個(gè)指針,指向一個(gè)對(duì)象,而這個(gè)對(duì)象的用途是包含可以由特定類型的所有實(shí)例共享的屬性和方法??慈缦吕樱?/p>

function Person(){
}
Person.prototype.name = 'ccc'
Person.prototype.age = 18
Person.prototype.sayName = function (){
 console.log(this.name);
}

var person1 = new Person()
person1.sayName() // --> ccc

var person2 = new Person()
person2.sayName() // --> ccc

console.log(person1.sayName === person2.sayName) // --> true

理解原型對(duì)象

根據(jù)上面代碼,看下圖:

JavaScript中原型和原型對(duì)象是什么

需要理解三點(diǎn):

  1. 我們只要?jiǎng)?chuàng)建了一個(gè)新的函數(shù),就會(huì)根據(jù)一組特定的規(guī)則為該函數(shù)創(chuàng)建一個(gè)prototype屬性,指向函數(shù)的原型對(duì)象。即Person(構(gòu)造函數(shù))有一個(gè)prototype指針,指向Person.prototype

  2. 默認(rèn)情況下,每個(gè)原型對(duì)象上都會(huì)創(chuàng)建一個(gè)constructor(構(gòu)造函數(shù))屬性,這個(gè)屬性是一個(gè)指向prototype屬性所在函數(shù)的指針

  3. 每個(gè)實(shí)例的內(nèi)部都有一個(gè)指針(內(nèi)部屬性) ,指向構(gòu)造函數(shù)的原型對(duì)象。即 person1 和person2 身上都有一個(gè)內(nèi)部屬性__proto__(在ECMAscript中管這個(gè)指針叫[[prototype]],雖然在腳本中沒有標(biāo)準(zhǔn)的方式訪問[[prototype]],但是firefox,ie,chrome都支持一個(gè)屬性叫__proto__) 指向Person.prototype


注意:person1 和person2 實(shí)例與構(gòu)造函數(shù)之間沒有直接的關(guān)系。

在之前我們提到,所有實(shí)現(xiàn)中無法訪問到[[prototype]],那我們?nèi)绾沃缹?shí)例和原型對(duì)象之間是否存在關(guān)系呢?這里可以通過兩個(gè)方法來判斷:

  • 原型對(duì)線上的方法:isPrototypeOf(),如:console.log(Person.prototype.isPrototypeOf(person1)) // --> true

  • ECMAscript5中新增的一個(gè)方法:Object.getPrototypeOf(),這個(gè)方法返回[[prototype]]的值。如:console.log(Object.getPrototypeOf(person1) === Person.prototype) // --> true


實(shí)例屬性與原型屬性的關(guān)系

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

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中添加一個(gè)name屬性
person1.sayName() // --> 'www'————'來自實(shí)例'
person2.sayName() // --> 'ccc'————'來自原型'

console.log(person1.hasOwnProperty('name')) // --> true
console.log(person2.hasOwnProperty('name')) // --> false

delete person1.name // --> 刪除person1中新添加的name屬性
person1.sayName() // -->'ccc'————'來自原型'

我們?nèi)绾闻袛嘁粋€(gè)屬性,到底是實(shí)例上的屬性還是原型上的屬性?這里可以通過hasOwnProperty()方法來檢測(cè)一個(gè)屬性是存在于實(shí)例中還是存在于原型中。(此方法繼承于Object)

下圖詳細(xì)分析了上面例子在不同情況下的實(shí)現(xiàn)與原型的關(guān)系:(省略了Person構(gòu)造函數(shù)的的關(guān)系)

JavaScript中原型和原型對(duì)象是什么

更簡(jiǎn)單的原型語法

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

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

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

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

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

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

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

function Person(){}
Person.constructor = {
 name: 'ccc', 
 age: 18,
 sayName: function(){
 console.log(this.name)
 }
}
// 重設(shè)構(gòu)造函數(shù),只適用于ECMAscript5兼容的瀏覽器
Object.defineProperty(Person.constructor, "constructor", {
 enumerable: false, 
 value: Person
})

原型的動(dòng)態(tài)性

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

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

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

function Person(){}
var person1 = new Person()

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

person1.sayName() // --> error

看下圖分析:

JavaScript中原型和原型對(duì)象是什么

調(diào)用構(gòu)造函數(shù)時(shí)為實(shí)例添加了一個(gè)指向最初原型的[[prototype]]指針,而把原型修改為另外一個(gè)對(duì)象就等于切斷了構(gòu)造函數(shù)與最初原型之間的聯(lián)系。請(qǐng)記?。簩?shí)例中的指針僅指向原型,而不指向構(gòu)造函數(shù)。

理解原型鏈

原型鏈?zhǔn)菍?shí)現(xiàn)繼承的主要方法。其基本思想是讓一個(gè)引用類型繼承另一個(gè)引用類型的屬性和方法。在理解原型鏈之前,我們首先得捋一下,原型,原型對(duì)象,實(shí)例之間的關(guān)系:每一個(gè)構(gòu)造函數(shù)都有一個(gè)原型對(duì)象,原型對(duì)象都包含一個(gè)指向構(gòu)造函數(shù)的指針,而實(shí)例都包含一個(gè)指向原型對(duì)象的內(nèi)部指針。假如我們讓原型對(duì)象等于另一個(gè)類型的實(shí)例會(huì)怎么樣?顯然,這個(gè)原型對(duì)象將會(huì)包含一個(gè)指向另一個(gè)原型的指針。先看代碼在看圖:

function SuperType(){
 this.property = true
}

SuperType.prototype.getSuperValue = function(){
 return this.property
}

function SubType(){
 this.subProperty = false
}

// 繼承了SuperType
SubType.prototype = new SuperType()

SubType.prototype.getSubValue = function (){
 return this.subProperty
}

var instance = new SubType()
console.log(instance.getSuperValue()) // --> true

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

JavaScript中原型和原型對(duì)象是什么

分析上圖:instance 指向SubType原型,SubType的原型又指向SuperType的原型。getSuperValue()方法仍然還在SuperType.prototype中,但property則位于SubType.prototype中。這是因?yàn)閜roperty是一個(gè)實(shí)例屬性,而getSuperValue()則是一個(gè)原型方法。既然SubType.prototype現(xiàn)在是SuperType的實(shí)例,那么property當(dāng)然就位于該實(shí)例中。此外要注意,instance.constructor現(xiàn)在指向的是SuperType,這是因?yàn)樵瓉淼腟ubType.prototype中的constructor被重寫了的緣故。
為什么會(huì)返回true?
分析:調(diào)用instance.getSuperValue()方法會(huì)經(jīng)歷三個(gè)搜索步驟:

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

別忘記默認(rèn)的原型

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

JavaScript中原型和原型對(duì)象是什么

詳細(xì)圖解:

JavaScript中原型和原型對(duì)象是什么

總之一句話,SubType繼承了SuperType,而SuperType繼承了Object。當(dāng)調(diào)用instanct.toString()的時(shí)候,實(shí)際上調(diào)用的是保存在Object.prototype中的那個(gè)方法。

確定原型和實(shí)例的關(guān)系

當(dāng)一個(gè)原型鏈很長(zhǎng)的時(shí)候,想要確定原型和實(shí)例的關(guān)系,總共有兩種方法:

使用instanceof 操作符,只要用這個(gè)操作符來測(cè)試實(shí)例與原型鏈中出現(xiàn)過的構(gòu)造函數(shù),結(jié)果就會(huì)返回true。

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

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

console.log(Object.prototype.isPrototypeOf(instance)) // --> true
console.log(SuperType.prototype.isPrototypeOf(instance)) // --> true
console.log(SubType.prototype.isPrototypeOf(instance)) // --> true

謹(jǐn)慎地定義方法

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

function SuperType(){
 this.property = true;
}
SuperType.prototype.getSuperValue = function(){
 return this.property
}

function SubType(){
 this.subProperty = false;
}

// 繼承了 SuperType
SubType.prototype = new SuperType()

// 添加新方法
SubType.prototype.getSubValue = function(){
 return this.subProperty
}
// 重寫超類型中的方法
SubType.prototype.getSuperValue = function(){
 return false
}

var instance = new SubType()
console.log(instance.getSuperValue()) // --> false
var instanceSuper = new SuperType()
console.log(instanceSuper.getSuperValue()) // -> true

上述代碼中,第一個(gè)方法getSubValue()被添加到了SubType中。第二個(gè)方法getSuperValue()是原型鏈中已經(jīng)存在的一個(gè)方法,但重寫這個(gè)方法將會(huì)屏蔽原來的那個(gè)方法。即當(dāng)通過SubType的實(shí)例調(diào)用getSuperValue()時(shí),調(diào)用的就是這個(gè)重新定義的方法,但通過SuperType的實(shí)例調(diào)用getSuperValue()時(shí),還會(huì)繼續(xù)調(diào)用原來的那個(gè)方法。還有一點(diǎn),在通過原型鏈實(shí)現(xiàn)繼承的時(shí)候,不能使用對(duì)象自變量創(chuàng)建原型方法,因?yàn)檫@樣會(huì)重寫原型鏈,導(dǎo)致原型鏈被切斷。

原型鏈的問題

通過原型來實(shí)現(xiàn)繼承時(shí),原型實(shí)際上會(huì)變成另一個(gè)類型的實(shí)例,于是,原先的實(shí)例屬性就變成了現(xiàn)在的原型屬性了,這就會(huì)導(dǎo)致屬性被共享。看如下代碼:

function SuperType(){
 this.colors = ['white', 'blue']
}

function SubType(){
}

// 繼承了SuperType
SubType.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"]

看完上述內(nèi)容是否對(duì)您有幫助呢?如果還想對(duì)相關(guān)知識(shí)有進(jìn)一步的了解或閱讀更多相關(guān)文章,請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝您對(duì)創(chuàng)新互聯(lián)網(wǎng)站建設(shè)公司,的支持。

分享題目:JavaScript中原型和原型對(duì)象是什么-創(chuàng)新互聯(lián)
網(wǎng)頁路徑:http://jinyejixie.com/article4/ghdie.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站建設(shè)、自適應(yīng)網(wǎng)站、做網(wǎng)站、軟件開發(fā)、動(dòng)態(tài)網(wǎng)站網(wǎng)站改版

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站優(yōu)化排名
汶上县| 孟州市| 庄浪县| 宁远县| 务川| 徐州市| 依兰县| 嘉鱼县| 凭祥市| 贞丰县| 靖西县| 汤阴县| 泰安市| 江山市| 论坛| 石柱| 兴义市| 焦作市| 五家渠市| 通州市| 凤山市| 西安市| 扶绥县| 武安市| 邵阳县| 广西| 永修县| 桦川县| 威信县| 芜湖市| 苍梧县| 阿勒泰市| 洛阳市| 稻城县| 施秉县| 巴东县| 化州市| 玉林市| 石狮市| 宿州市| 绥滨县|