1. 程式人生 > >JS難點剖析-原型&原型鏈

JS難點剖析-原型&原型鏈

 js的原型&原型鏈&閉包,在很多人看來是區分JS程式設計師水平的關鍵知識點,當然對這句話我不是十分贊同。但是掌握這幾個核心知識點總是沒錯滴!

    直接上程式碼:

<script type="text/javascript">

//全部為函式物件型別(function)
function f1(){}
var f2 = function(){}
var f3 = new Function() 

//全部都是普通物件型別(object)
var o1 = {}
var o2 = new Object()
var o3 = new f1()

console.info(
  typeof f1,
  typeof f2,
  typeof f3,
  typeof o1,
  typeof o2,
  typeof o3
)

//function function function object object object

var obj = new f1();
f1.prototype.name = 'banyoukang';
console.info(obj.__proto__.name)//banyoukang
console.info(f1.prototype)// f1 { name="banyoukang"}
console.info(obj.__proto__)//f1 { name="banyoukang"}

</script>

你可以自己試試這段程式碼,並想一下其輸出結果,為什麼?下面讓我們掰扯掰扯這段程式碼:

  1. 關於JavaScript物件
    在JavaScript中,一切都是物件,但是和Java不同的是:這些物件是分型別的。主要分為function(函式物件)和object(普通物件)。

    //全部為函式物件型別(function)
    function f1(){}
    var f2 = function(){}
    var f3 = new Function()
    
    //全部都是普通物件型別(object)
    var o1 = {}
    var o2 = new Object()
    var o3 = new f1()
    
         

    <1>在這裡,f1應該是我們開發中最常用法,f2用的應該也挺多,只是多了一個引用罷了。但是,f3這種寫法倒是不多見的,其實f1,f2在建立的時候,JS會自動通過new Function()的方式來構建這些物件,所以都是f1,f2,f3本質上並沒有什麼區別。注:

    var f3 = new Function('var temp = 100; this.temp = 200; return temp + this.temp;');

     

    alert(f3())

    //彈出300,()將會執行引號中的內容,類似於eval函式)

    <2>關於o1和o2我們都可以理解(物件字面量、使用new表示式來建立物件

    ),但是o3雖然是f1函式new出來的,但是和f1缺不是一個型別的,看列印結果可以發現,一個是函式物件一個是普通物件。

  2. 關於原型和原型鏈

          在JavaScript中,每一個物件都有一些屬性,包括prototype和__proto__,其中prototype就是原型物件(prototype其實就是函式的一個屬性),其作用就是儲存物件的一些屬性和方法(你可以通過f1.prototype.show = function(){} 給f1的prototype賦值一個方法),但是prototype對於物件本身是隱藏起來的,因為它是原型物件prototype的屬性而不是物件本身的屬性(你可以通過f1.prototype.show()來呼叫,但是不能通過f1.show()來呼叫)。關於__proto__,這才是原型鏈真正起作用的地方,它在普通物件和函式物件中都存在, 它的作用就是儲存父類的prototype物件,JS在通過new 表示式建立一個物件的時候,通常會把父類的prototype賦值給新物件的__proto__屬性,這樣,就形成了一代代傳承...  

function f2(){}
f2.prototype.name='banyoukang';
var test = new f2();

console.info(test.name)//banyoukang

    注:可以通過test.__proto__來檢視原型鏈

        

        _proto_儲存著父類的prototype的屬性,當查詢一個屬性的時候,先看看自己有沒有這個屬性,如果沒有就順著原型鏈往上依次查詢(注:不會查詢自身的prototype屬性)。

3.總結

        <1>prototype就是物件的一個屬性,這個屬性也是一個物件(類似Java類中把其他類的物件定義成一個成員變數),專門用於儲存準備傳遞到子類的方法和屬性。

        <2>__proto__就是prototype中屬性和方法的實際傳遞者,當你new一個物件的時候,會把父類的prototype賦值給新物件的__proto__屬性,這樣你在子類的__proto__屬性中就可以拿到父類傳給你的屬性和方法。

        <3>不同的物件的原型鏈是截然不同的,比如父類和子類:

            function f1(){}

            var test = new f1()

        f1的原型鏈:f1->Function.prototype->Object.prototype->null

        test的原型鏈:test->f1.prototype->Object.prototype->null

        從上面的例項我們可以看到:物件的prototype屬性是為子類服務的,是子類建立的核心,決定了子類的資料型別

 

        這篇博文是自己試驗加上閱讀其他大神的部落格總結出來的,如果您閱讀的過程中發現其中存在問題或者有指教的地方,歡迎拍磚,共同進步!