1. 程式人生 > >詳解Ext.extend 函式

詳解Ext.extend 函式

  •   

      這段程式碼是Ext核心包中的關於繼承的方法,其作用是利用JS中的原形繼承來實現Ext中的JS類繼承。由於JS中的原形繼承和傳統的面向物件程式的類繼承有較大差別我們這裡需要梳理JS中的關於比較核心的知識點:

  • js中怎樣寫一個類?

    js中的並沒有用專門的關鍵字來作為描述類的符號,儘管"class"在javascript中是作為保留字,但在javascript中描述一個類並不是用"class"而是用"function".下面我們就來寫一個例子類.

       這就是一個描述"人"的類,它只有一個屬性就是"name".雖然它通常是被認是是函式,但事實上在javascript中我們要寫一個類時,就是這樣寫的。同時在下面我們還通過這個類new 了一個它的物件"p".這看起來跟JAVA 或 c++都有點相似。然後我們打印出了p的name屬性,從這相結果中,我們可以看出作為構造類的函式,實際上比較類似於面象物件中的建構函式。也就是說我們在呼叫new Person('andy')的時候執行的就是那段函式.這個物件現在還沒任何動作,我們來給它增加一個動作:

這樣就給Person類增加了一個叫"eat"的動作,但是記住我們給類增加一個方法不能這麼加:

這樣是錯誤的,第一種增加動作的方法是正確的是因為,在建構函式裡有這麼一句this.eat = function(){....} ,這是一種顯示的給類加動作的方法,而第二種增加動作的方法之所以不正確,這是由JS的原形繼承的機制決定的。什麼叫“原形”下面我們就來引入這一概念:

  • 關於"prototype"

     prototype即是我們說的“原形",javascript中的每一個類都有一個prototype,prototype是一個JS物件。它的作用相當於是一個模板,所有類的物件,都關複製了這個模板,所以只要是模板中含有的屬性,所有的物件都具有,只要是模板具有的動作,所有的物件也都具有。

從上面,可以看出prototype確實相當於一個模板,所有類的物件都複製了這個模板,然而我們也看出並不是類的所有屬性都在prototype中,比如說先前我們加入的name屬性和eat方法,這也可見往一個類中增加屬性和方法有兩種方法一種是在建構函式中加入,另一種則是在prototype這個模板物件中加入.

在Body中有prototype這個屬性,p 在構造的時候複製了這個屬性,但如果用alert(p.prototype);語句我們打印出來的卻是"undefined",為什麼呢,因為在javascript中prototype是隱藏在每個物件中的,作為一個內部原形.

  • 關於constructor

上面我們詳解了prototype ,但是prototype內部有一個比較特殊的方法,它就是constructor,先看下面的程式碼:

執行上面程式碼,我們看到這個所謂的constructor函式就是Person類的建構函式,而且在物件p中也有一個這樣的constructor方法,其實也好解釋,為什麼呢?我們之前說過了,每個物件會複製一份prototype的模板,prototype中有的方法和屬性也就成了物件自己的方法和屬性了,既然Prototype中有constructor這樣一個方法,那自然每個物件中也有這樣一個方法了.

    這裡就有了一個問題,原形中的constructor既然預設就是類的建構函式,那麼我們能不能改變這個預設的方法,答案是肯定的,我們可以將它替換成另一個我們自己定義的方法,這樣每個物件的constructor方法也成了我們自定義的方法,但如果替換了之後,我們在new 一個物件時執行的是哪個方法呢?可以通過程式碼驗證:

可以看到雖然我們替換了prototype的constructor但是在new 一個物件的時候,仍然執行的是我們定義一個類時的函式。也就是Person函式本身.

上面是關於javascript中原形繼承知識的一些講解,如果明白了這些底層的知識,那麼讀懂Ext.extend方法就並不難了,我只講講這個方法做了哪些事:

1.將子類的prototype複製為跟超類一模一樣,但是請注意我這裡說提複製,並沒有把超類的prototype直接賦給子類的prototype,而且程式碼裡也作的很精巧,這裡可能有一點難看懂。同時,把子類原形的constructor指向子類建構函式本身.

2.檢查超類的constructor是不是等於Object.prototype.constructor,如果是,則將它指向為超類本身的建構函式.

3.在子類的prototype中 加入了override方法,這樣就在每個子類的物件中都可以用這個方法.

4.給子類本身加入了override和extend方法,記住這裡是給類本身,而不是在prototype中增加的方法,所以在子類的物件中是不能呼叫的。

5.將引數override中的發生,複製到子類的prototype中去,關於這一點,需要大家認真的看Ext.override這個方法的原碼.