Js 原型對象與原型鏈

來源:互聯網
上載者:User

標籤:ons   strong   構造器   使用   技術   也有   log   object   構造   

原型對象

  每個javascript對象都有一個原型對象,這個對象在不同的解譯器下的實現不同。比如在firefox下,

每個對象都有一個隱藏的__proto__屬性,這個屬性就是“原型對象”的引用。

原型鏈

  由於原型對象本身也是對象,根據上邊的定義,它也有自己的原型,而它自己的原型對象又可以有自

己的原型,這樣就組成了一條鏈,這個就是原型鏈,JavaScritp引擎在訪問對象的屬性時,如果在對象本

身中沒有找到,則會去原型鏈中尋找,如果找到,直接傳回值,如果整個鏈都遍曆且沒有找到屬性,則返

回undefined.原型鏈一般實現為一個鏈表,這樣就可以按照一定的順序來尋找。

我們先用一個構造器來實現一個建構函式:

function A(){    this.mark = "A";    this.changeMark = function(){        this.mark += "_changed";    }}A.prototype.mark2 = "A2";A.prototype.changeMark2 = function(){    this.mark2 += "_changed";}var a = new A();var a2 = new A();//下面則說明建構函式執行個體化後,分配著不同的執行個體對象,互不相關console.log(a.mark);  //"A"console.log(a2.mark); //"A"    a.changeMark();   //使用執行個體對象中的方法console.log(a.mark);  //"A_changed"console.log(a2.mark); //"A"//下面則說明了new操作符的一項作用,即將原型中的this指向當前對象,//在a.changeMark2執行時,changMark2中的方法先找 this.mark2 的值,//但是執行個體對象this中沒有mark2值,則在原型鏈向上尋找,得到A原型對象中的mark2值,//在賦值時,將修改後的值添加在了a執行個體中。//總:雖然調用的是prototype方法,但是不會對prototype屬性做修改,只會說是在執行個體中新增屬性,但是在使用時,會最使用最近得到的屬性(在後面原型鏈中可以加以理解)console.log(a.mark2);  //"A2"console.log(a2.mark2); //"A2"    a.changeMark2();   //使用原型鏈中的方法console.log(a.mark2);  //"A2_changed"console.log(a2.mark2); //"A2"

為什麼a可以使原型中的changeMark2方法?這就和js巧妙的原型鏈相關,在Firefox中我們可以列印出對象並可查看到對象下面的__proto__。

我們把上面的過程用流程圖來表示:

 

 

 

只有建構函式才會有prototype屬性,而執行個體化出來的對象會擁有__proto__,而不會有prototype。

像畫的那樣,兩個執行個體化的對象都通過__proto__屬性指向了A.prototype(即建構函式的原型對象)

而原型對象的__proto__指向Object對象,就像a.toString()的toString方法就是存在於Object原型對象(Object.prototype)中。

 

so:當使用對象的方法或屬性時,對象會在一步一步通過__proto__向上尋找,找到最近的則是最終的擷取到的方法或屬性。

  ————這就是js中的原型鏈。

 就像圖上看到的一樣,所有對象的原型鏈最終都指向了Object對象,而Object的原型對象(Object.prototype)是為數不多的不繼承自任何屬性的對象,即Object.prototype沒有__proto__,是原型鏈的頂峰。

通過上面我們可以瞭解到,當我們對A.prototype或Object.prototype添加屬性或方法時,在a和a2執行個體中都會查看到該屬性或方法,因為這兩個執行個體都通過原型鏈與A和Object的原型對象相連。

 

 再來看看原型對象和原型鏈在繼承方面的實現:

再構造一個函數A和一個函數B,並讓B繼承A,如下:

 

function A(mark){    this.mark = mark;}A.prototype.getMark = function(){    return this.mark;}function B(mark){  this.mark = mark}//var temp = new A("A");//B.prototype = temp;//上面語句和下語句作用相同B.prototype = new A("A"); //執行個體化一個A,其賦值於B.prototypevar b = new B("B");console.log(b.mark); //B, 結果如上面原型鏈分析的那樣,向上找到最近的屬性,則為b執行個體中的mark:"B"

 

其中的結構示意大概如:

 

這時我們可以看到,在B.prototype中是沒有constructor的,因為B.prototype只是簡單的new A("A")對象賦值的結果。

在js中的constructor有什麼作用呢?如:

var arr = new Array();arr instanceof Array;      //truearr.constructor === Array; //truefunction TEMP(){}var temp = new TEMP();temp instanceof TEMP;      //truetemp.constructor === TEMP; //true

 

用《JavaScript權威指南》中的對於constructor的解釋為:對象通常繼承的constructor均指代它們的建構函式,而建構函式是類的“公用標識”。即constructor可用來判斷對象所屬的類。

 

在上面的小例子中,用instanceof也可判斷對象的類,但是有自身的缺陷,instanceof的實現方法為:

instanceof不會去檢查temp是不是由TEMP()建構函式初始化的,面是判斷temp是否繼承自TEMP.prototype,這樣,範圍就寬了很多。

如在上面的大例中,使用

b instaceof B //true 因為在b的原型鏈中可以找到B.prototype對象 b instaceof A //true 在b的原型鏈中也可以找到A.prototype對象

  可以說instanceof是用來檢測繼承關係的。而當

console.log(b.constructor) //function A()//因為在b的原型鏈中,最近的constructor就是A.prototype中有constructor指向了建構函式A();

  但我們知道的b是屬於B類的,那最後所以要做的就是:

B.prototype.constructor = B; //將constructor指向自身的建構函式var new_b = new B("B");console.log(new_b.constructor) //function B() 

  

 

 

 

 

 

 

 

Js 原型對象與原型鏈

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.