javascript prototype 學習

來源:互聯網
上載者:User

http://www.cnblogs.com/birdshome/archive/2005/02/17/105403.html

原型(prototype)是JavaScript實現物件導向編程的一個基礎,但它並不是唯一的構造類的方法,我們完全可以不使用prototype而實作類別的編寫(把屬性和方法的附加全都寫在建構函式裡面就行了)。不過原型除了可以為Object的子類添加新的屬性和方法外,它還可以為指令碼環境中的內部對象繼續添加原型屬性和方法,比如我們最常用的給內部對象String添加一個Trim方法來刪除字串兩端的空格,代碼為:

   String.prototype.Trim = function()
   {
        return this.replace(/(^\s*)|(\s*$)/g, '');
   }

   這樣我們就可以在任何的String執行個體中使用Trim方法了,用慣了這種原型系統,有的時候反而還覺得傳統OOP沒有它爽,kaka。言歸正傳,繼續講我們的原型繼承法。

原型繼承法的原理:

    原型繼承法的關鍵代碼是其建構函式function ArrayList02()下的第一句:

   ArrayList02.prototype = new CollectionBase();
   ArrayList02.prototype.constructor = ArrayList02;

Ae… 把prototype都覆蓋成基類的一個執行個體了,子類還怎麼使用prototype呢?這裡不要著急,反正JavaScript的對象執行個體都是可以動態增刪屬性和方法的,基類執行個體作為prototype不就正好等於extends了CollectionBase嗎?之後再使用XXX.prototype.xxx = function(),可以繼續獲得新增了屬性和方法的對象。注意ArrayList02.prototype是在ArrayList02的建構函式外被初始化為基類的執行個體的

    再來看第二句,為什麼要把ArrayList02賦值給新prototype的constructor呢?如果不做這個賦值,當我們從ArrayList02的執行個體中,通過???.prototype.constructor去卻其建構函式,將會獲得CollectionBase。這不是我們的本意,而且這是使用instanceof關鍵之比較對象執行個體和對象也會出錯。

    原型繼承法的缺陷:

    原型繼承法有兩個缺陷,第一個是由於類的原型(prototype)實際上是一個Object的執行個體,它不能再次被執行個體化(它的初始化在指令碼裝載時已經執行完畢)。這麼意思呢?我們知道在建立對象執行個體時,我們使用語句new ArrayList02(),這時我們可以看做JavaScript指令碼引擎把prototype的一個淺拷貝作為this返回給類的執行個體(這裡其實沒有發生拷貝,只是利用淺拷貝這個概念來協助理解),如果類沒有附加任何原型屬性和原型方法,那麼就等於返回了一個new Object()執行個體。問題就出在這裡了,由於new對prototype執行的是淺拷貝,如果prototype的原型屬性裡有物件類型的屬性,那麼就會造成共用對象執行個體的問題(類似於在傳統OOP的類定義中使用了static修飾符來修飾了屬性)。這個缺陷下面會有樣本示範,避免的辦法就是不要在基類中定義物件類型的屬性,比如: Array、Object和Date等。
    第二個缺陷和上次講的"構造繼承法"的缺陷差不多,也是關於子類定義是語句順序的。就是說代碼:ArrayList02.prototype = new CollectionBase();必須在所有prototype定義之前執行,很簡單,如果在原型屬性和方法都匯入完成後,再執行這個語句,就定於把之前的匯入全都覆蓋掉了:(。解決辦法就是按我給文章(1)中的那個順序來寫,鬱悶吧?kaka

    原型繼承法的樣本:

<script language="JavaScript">
document.write('原形繼承法:<br>'); 
var arrayList21 = new ArrayList02();
arrayList21.Add('a');
arrayList21.Add('b');
arrayList21.foo();
var arrayList22 = new ArrayList02();
arrayList22.Add('a');
arrayList22.Add('b');
arrayList22.Add('c');
arrayList22.foo();
</script>

 

    樣本運行結果為:

 

原形繼承法:
[class ArrayList02]: 2: a,b
[class ArrayList02]: 3: a,b,c,a,b

 

    發現問題了吧?執行個體arrayList22的foo()居然輸出了a,b,c,a,b@_@... 這就是前面說的prototype對象淺拷貝帶來的問題。不過為什麼arrayList22中的集合計數器卻仍然是3呢?這是因為this.m_Count是整數類型,這種類型又叫實值型別(和C#裡的實值型別、物件類型概念一樣的)。實值型別不存在淺拷貝和深拷貝的問題,可以看成都是深拷貝。

    小結:JavaScript的原型繼承法,雖然有prototype淺拷貝那麼嚴重的bug,不過它卻是使用比較多的繼承方式。因為我們很少在基類裡定義屬性,更別說物件類型的屬性了,所以引發這個錯誤的可能性不是很大,只是它是個潛在的隱患:(。至於第二個缺陷,也是一個潛在bug,只要自己定義類的時候能比較清醒就不會犯錯誤。'重載'也比較簡單,如果在ArrayList02.prototype = new CollectionBase();後有重名的屬性或方法匯入,自動覆蓋基類中的屬性或方法就像當於重載了。

    應用情境:基類沒有屬性,至少是要沒有物件類型的屬性。這種繼承的優點是保持了子類建構函式的完整,可以不在裡面添加任何和繼承有關係的代碼,所有繼承和重載操作都由對原型(prototype)的操作來完成。

 

我們知道JScript中對象的prototype屬性,是用來返回物件類型原型的引用的。我們使用prototype屬性提供對象的類的一組準系統。並且對象的新執行個體會"繼承"賦予該對象原型的操作。

下面我們看三個經典的prototype屬性的使用樣本。

    1、為指令碼環境內建對象添加方法:

 Array.prototype.max = function()
 {
     var i, max = this[0];
     for (i = 1; i < this.length; i++)
     {
        if (max < this[i])
        max = this[i];
     }
     return max;
 };

 2、為使用者自訂類添加方法:

 function TestObject(name)
 {
     this.m_Name = name;
 }

 TestObject.prototype.ShowName = function()
 {
     alert(this.m_Name);
 };

3、更新自訂類的prototype:

 function TestObjectA()
 {
    this.MethodA = function()
    {
       alert('TestObjectA.MethodA()');
    }
 }

 function TestObjectB()
 {
    this.MethodB = function()
    {
       alert('TestObjectB.MethodB()');
    }
 }

 TestObjectB.prototype = new TestObjectA();

 第三個很眼熟吧?對啊,它就是我們前面介紹的原型繼承法呀~~ 不過今天我們不是研究"繼承",之所以可以這樣來實現一種繼承,只是利用了prototype屬性的一個副作用而已。
  prototype還有一個預設的屬性:constructor,是用來表示建立對象的函數的(即我們OOP裡說的建構函式)。constructor屬性是所有具有prototype屬性的對象的成員。它們包括除Global和Math對象以外的所有JScript內部對象。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.