posts - 310, comments - 6939, trackbacks - 0, articles - 3
            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

          JavaScript Prototype 詳解(轉載)

          Posted on 2009-04-26 16:54 詩特林 閱讀(5302) 評論(1)  編輯  收藏 所屬分類: JavaScript

          本文里講述的是關于JavaScript的prototype問題,至于具體的JavaScript面向對象的編程教程,請各位看客到其他網站搜索一下,或者到這里看看。

          首先開始一個例子,如下:


          1 function A() {
          2     this.t1 = "ffffff";
          3     this.t2 = function (msg) {
          4         alert(msg);
          5     };
          6 };
          7
          8 A.prototype.p1 = "xxxx";
          9
          10 A.prototype.f1 = function () {
          11      do something.
          12 };
          其實p1,f1是對function的prototype對象的操作,大家要明白,function
          也是一個對象,對象也有屬性,而prototype就是function的屬性,該屬性
          也是一個對象,不同之處是,function在做為類定義的時候,創建類實例的
          過程(new的過程)要參照它的prototype對象,把prototype對象的所有
          屬性(也就是Java里的成員,包括成員變量和成員函數)都復制到新的對象
          中去,所以可以看出prototype就是模板,而這個模板是在new一個對象之
          前就已經存在了。

          上面的JavaScript就好像在定義一個Java類,書寫類的時候,除了用不同的聲明
          (Class和Function)區別,基本沒有其他的區別,但在運行時有很大的區別。
          首先Java要求類必須被編譯成字節碼才能被載入虛擬機,而JavaScript是在運行
          代碼的同時,執行了類似Java的編譯載入的過程。并且Java的類在載入虛擬機
          后一般就不能再改變類的定義了,比如把一個方法的行為改變或指向另一個方
          法的引用等。而JavaScript在運行期還可以通過prototype來改變類及所有該類生成
          的對象的行為。例如上面的例子中,在解析完function A的函數體后,整個類也
          就生成了,這時候如果new的話就能得到類的實例,緊接著的代碼又向類動態
          添加了新的行為。

          而在function A的函數體內定義的this成員,可以理解為‘后’綁定成員。
          可以這么理解,在new A()的時候JavaScript建立了一個臨時對象,
          把A.prototype的所有成員復制到臨時對象中,然后再把函數A中
          定義的this成員也綁定到臨時對象中,然后把臨時對象返回給用戶。
          下面是模擬JavaScript的new關鍵字的處理偽過程:

          //建立臨時對象
          var tobj = {};
          //復制prototype
          for (var key in A.prototype)
          tobj[key] = A.prototype[key];
          //綁定函數體內的this成員(這個過程是JavaScript的內部處理,沒有辦法模擬)
          return tobj to user;

          之所以存在function內部定義的this成員,以及prototype的成員是
          有原因的。由于JavaScript的類在構造時是可以傳遞構造參數的,
          所以,this成員的行為可能由于參數的不同而不同。這也就是需要后
          綁定的原因了。在看下一個例子:

          1 function AA(val1,val2) {
          2     this.test1 = function() {
          3         alert(val1);
          4     };
          5
          6     this.test2 = val2 ? function () { return this.test1;} : function () { return 456; };
          7
          8     this.test3 = val1 ? val1 : function () {alert("no val1");};
          9 }
          這個例子很好的說明了后綁定的實際使用價值,所以后綁定對于成員
          函數來說是非常有用的,對于成員變量來說其實沒什么實際用處。
          唯一不同的是,this成員在每次new對象時都要被JavaScript引擎解析,
          原因很簡單,根據不同的構造參數,使它們在運行期的行為可能有很大
          的不同。而prototype的成員就不會每次都解析,第一次定義prototype
          成員時才解析,以后可以直接引用prototype成員,并且更改了prototype
          成員,所有已經建立的實例對象的相應成員都會被更改。

          在運行期可以通過'對象名.成員名'來更改成員,這種方式可以更改this成員
          和prototype成員的默認定義,但是更改只限于自身對象,因為JavaScript
          和Java一樣,也是傳值,對象的引用也是一個地址值,所以new一個對象后,
          prototype的成員也被復制到那個對象上了,再更改那個對象的成員,只會
          影響那個對象自身,其他從同一個類new出來的對象都不會有任何變化。

          不能通過運行期設置'類.prototype.成員名'來覆蓋this同名成員,這樣做沒有
          任何效果。

          通過復制一個對象的所有屬性到一個新對象,是不能通過修改prototype成員
          來修改新對象的成員行為,因為新對象不是通過原來對象的類new出來的。
          通常的復制方法如下:

          1 var tobj = {};
          2 for (var key in otherObj)
          3     tobj[key] = otherObj[key];
          看似tobj和otherObj的行為是一致的,他們不是一個類new出來的。
          一個很好的辦法可以測試,比如otherObj是A類new出來的,
          可以通過使用 (tobj instanceof A) 來測試,結果顯然是false。

          最新的測試表明,這種復制方法可以復制所有自定義方法,
          但是系統提供的默認方法是不能被復制的,即使你顯式的覆蓋了
          系統默認提供的方法,如toString方法等。

          最后再談談prototype的constructor成員,該成員是對一個類的構造
          函數的引用,在類定義的初期,如果一個類沒有從其他別的類那
          里繼承,該類的prototype.constructor屬性保存的是該類自身的引用,
          如果該類從別的類繼承,那么它的constructor屬性就保存了父類的
          constructor引用,一般constructor沒有什么用處,但可以通過它來取
          得他的類的信息,就像Java里的對象都有getClass()方法,constructor
          就是干這個用的。有它的好處是,再運行期可以改變所有同類對象
          的成員行為,如:

          1 someObj.constructor.prototype.somePrototype = function () {
          2 other process .
          3 }
          因此好的習慣是在繼承之后把prototype的constructor成員設置一下,
          否則會把父類的prototype成員改掉,那樣程序的行為就不可預知了。
          如:

          1 function classA() {
          2
          3 }
          4
          5 classB.prototype = new classA();
          6 classB.prototype.constructor = classB;
          7
          我要說的關于JavaScript的prototype屬性就這么多,大家多提意見多交流。


          評論

          # re: JavaScript Prototype 詳解(轉載)  回復  更多評論   

          2011-11-05 18:24 by 范秋海
          有錯誤。
          例如:
          var A = function(a){this.a = a};
          A.prototype.b = 0;
          var a1 = new A(1); a1.b = 2;
          var a2 = new A(2);
          alert(a1.a) 輸出1,
          alert(a1.b) 輸出2
          alert(a2.a) 輸出2
          alert(a2.b) 輸出0

          但是如果是這種情況:
          var A = function(a){this.a = a};
          A.prototype.b = {};
          var a1 = new A(1); a1.b.b = 2;
          var a2 = new A(2);
          alert(a1.a) 輸出1,
          alert(a1.b.b) 輸出2
          alert(a2.a) 輸出2
          注意:
          alert(a2.b.b) 輸出2
          主站蜘蛛池模板: 临城县| 台湾省| 永靖县| 濉溪县| 西和县| 林州市| 平泉县| 宜宾县| 康保县| 双江| 藁城市| 定州市| 乳山市| 沾化县| 龙岩市| 宿迁市| 大港区| 塘沽区| 报价| 宜宾县| 永康市| 房山区| 定边县| 安仁县| 乌拉特后旗| 通许县| 拜城县| 洞头县| 东方市| 大石桥市| 彝良县| 万荣县| 周口市| 巴里| 杨浦区| 梧州市| 亚东县| 兰州市| 延边| 湘西| 古浪县|