Javascript屬性constructor/prototype的底層原理

來源:互聯網
上載者:User

在Javascript語言中,constructor屬性是專門為function而設計的,它存在於每一個function的prototype屬性中。這個constructor儲存了指向function的一個引用。在定義一個函數(代碼如下所示)時,

function F() {
// some code
}

JavaScript內部會執行如下幾個動作:
為該函數添加一個原形屬性(即prototype對象).
為prototype對象額外添加一個constructor屬性,並且該屬性儲存指向函數F的一個引用。

這樣當我們把函數F作為自訂建構函式來建立對象的時候,對象執行個體內部會自動儲存一個指向其建構函式(這裡就是我們的自訂建構函式F)的prototype對象的一個屬性__proto__,所以我們在每一個對象執行個體中就可以訪問建構函式的prototype所有擁有的全部屬性和方法,就好像它們是執行個體自己的一樣。
當然該執行個體也有一個constructor屬性了(從prototype那裡獲得的),這時候constructor的作用就很明顯了,因為在這時,每一個對象執行個體都可以通過constrcutor對象訪問它的建構函式,請看下面代碼:




[javascript] view plaincopy




var f = new F();
alert(f.constructor === F);// output true
alert(f.constructor === F.prototype.constructor);// output true


我們可以利用這個特性來完成下面的事情: 物件類型判斷,如



[javascript] view plaincopy




if(f.constructor === F) {
// do sth with F
}


其實constructor的出現原本就是用來進行物件類型判斷的,但是constructor屬性易變,不可信賴。
我們有一種更加安全可靠的判定方法:instanceof 操作符。
下面代碼仍然返回true

if(f instanceof F) {
// do sth with F
}.

原型鏈繼承,由於constructor存在於prototype對象上,因此我們可以結合constructor沿著原型鏈找到最原始的建構函式,如下面代碼:

function Base() {
}
// Sub1 inherited from Base through prototype chain
function Sub1() {
}
Sub1.prototype = new Base();
Sub1.prototype.constructor = Sub1;
Sub1.superclass = Base.prototype;
// Sub2 inherited from Sub1 through prototype chain
function Sub2() {
}
Sub2.prototype = new Sub1();
Sub2.prototype.constructor = Sub2;
Sub2.superclass = Sub1.prototype;
// Test prototype chain
alert(Sub2.prototype.constructor);
// function Sub2(){}
alert(Sub2.superclass.constructor);
// function Sub1(){}
alert(Sub2.superclass.constructor.superclass.constructor);
// function Base(){}

上面的例子只是為了說明constructor在原型鏈中的作用,更實際一點的意義在於:一個子類對象可以獲得其父類的所有屬性和方法,稱之為繼承,關於繼承我們有好多可以分析和討論,本篇限於篇幅不在此討論。
一個容易掉入的陷阱(gotchas) 之前提到constructor易變,那是因為函數的prototype屬性容易被更改,我們用時下很流行的編碼方式來說明問題,請看下面的範例程式碼:

function F() {

}
F.prototype = {
_name:Eric,
getName: function () {
return this._name;
}
}

初看這種方式並無問題,但是你會發現下面的代碼失效了:
var f = new F();
alert(f.constructor === F); // output false
怎麼回事?F不是執行個體對象f的建構函式了嗎?
當然是!只不過建構函式F的原型被開發人員重寫了,這種方式將原有的prototype對象用一個對象的字面量{}來代替。
而建立的對象{}只是Object的一個執行個體,系統(或者說瀏覽器)在解析的時候並不會在{}上自動添加一個constructor屬性,因為這是function建立時的專屬操作,僅當你聲明函數的時候解析器才會做此動作。
然而你會發現constructor並不是不存在的,下面代碼可以測試它的存在性:
alert(typeof f.constructor == ‘undefined’);// output false
既然存在,那這個constructor是從哪兒冒出來的呢?
我們要回頭分析這個對象字面量{}。
因為{}是建立對象的一種簡寫,所以{}相當於是new Object()。
那既然{}是Object的執行個體,自然而然他獲得一個指向建構函式Object()的prototype屬性的一個引用__proto__,又因為Object.prototype上有一個指向Object本身的constructor屬性。所以可以看出這個constructor其實就是Object.prototype的constructor,下面代碼可以驗證其結論:
alert(f.constructor === Object.prototype.constructor);//output true
alert(f.constructor === Object);// also output true
一個解決辦法就是手動恢複他的constructor,下面代碼非常好地解決了這個問題:

function F() {
}
F.prototype = {
constructor: F, /* reset constructor */
_name: Eric,
getName: function () {
return this._name;
}
};

之後一切恢複正常,constructor重新獲得的建構函式的引用,我們可以再一次測試上面的代碼,這次返回true
var f = new F();
alert(f.constructor === F); // output true this time ^^
解惑:建構函式上怎麼還有一個constructor?它又是哪兒來的?
細心的朋友會發現,像JavaScript內建的建構函式,如Array, RegExp, String, Number, Object, Function等等居然自己也有一個constructor:
alert(typeof Array.constructor != ‘undefined’);// output true
經過測試發現,此物非彼物它和prototype上constructor不是同一個對象,他們是共存的:
alert(typeof Array.constructor != ‘undefined’);// output true
alert(typeof Array.prototype.constructor === Array); // output true
不過這件事情也是好理解的,因為建構函式也是函數。
是函數說明它就是Function建構函式的執行個體對象,自然他內部也有一個指向Function.prototype的內部引用__proto__啦。
因此我們很容易得出結論,這個constructor(建構函式上的constructor不是prototype上的)其實就是Function建構函式的引用:
alert(Array.constructor === Function);// output true
alert(Function.constructor === Function); // output true

OK, constructor從此真相大白,你不在對它陌生了

本文

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.