亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

詳解js中的原型,原型對象,原型鏈

 更新時間:2020年07月16日 08:35:15   作者:菜小牛  
這篇文章主要介紹了js中的原型,原型對象,原型鏈的相關資料,文中講解非常細致,代碼幫助大家更好的理解和學習,感興趣的朋友可以了解下

理解原型

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

理解原型對象

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

需要理解三點:

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

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

在之前我們提到,所有實現(xiàn)中無法訪問到[[prototype]],那我們?nèi)绾沃缹嵗驮蛯ο笾g是否存在關系呢?這里可以通過兩個方法來判斷:

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

實例屬性與原型屬性的關系

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

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'))  // --> true
console.log(person2.hasOwnProperty('name'))  // --> false

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

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

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

更簡單的原型語法

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

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

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

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操作符測試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)
 }
}
// 重設構造函數(shù),只適用于ECMAscript5兼容的瀏覽器
Object.defineProperty(Person.constructor, "constructor", {
 enumerable: false, 
 value: Person
})

原型的動態(tài)性

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

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

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

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

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

person1.sayName()  // --> error

看下圖分析:

調(diào)用構造函數(shù)時為實例添加了一個指向最初原型的[[prototype]]指針,而把原型修改為另外一個對線更久等于切斷了構造函數(shù)與最初原型之間的聯(lián)系。請記?。簩嵗械闹羔槂H指向原型,而不指向構造函數(shù)。

原型鏈

簡單的回顧一下構造函數(shù)、原型和實例的關系:每個構造函數(shù)都有一個原型對象,原型對象都包含一個指向構造函數(shù)的指針,而實例都包含一個指向原型對象的內(nèi)部指針。那么假如我們讓原型對象等于另一個類型的實例,結果會怎樣?顯然,此時的原型對象將包含一個指向另一個原型的指針,相應地,另一個原型中也包含著一個指向另一個構造函數(shù)的指針。假如另一個原型又是另一個類型的實例,那么上述關系依然成立。如此層層遞進,就構成了實例與原型的鏈條。這就是所謂的原型鏈的基本概念。

圖中由相互關聯(lián)的原型組成的鏈狀結構就是原型鏈,也就是藍色的這條線。

以上就是詳解js中的原型,原型對象,原型鏈的詳細內(nèi)容,更多關于js中的原型,原型對象,原型鏈的資料請關注腳本之家其它相關文章!

相關文章

最新評論