<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    ALL is Well!

    敏捷是一條很長的路,摸索著前進著

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      30 隨筆 :: 23 文章 :: 71 評論 :: 0 Trackbacks

    更加內容參見w3school:http://www.w3school.com.cn/js/pro_js_object_defining.asp

    注:ECMAScript即JavaScript核心。

    使用預定義對象只是面向對象語言的能力的一部分,它真正強大之處在于能夠創建自己專用的類和對象。

    ECMAScript 擁有很多創建對象或類的方法。

    工廠方式
    原始的方式
    因為對象的屬性可以在對象創建后動態定義,所有許多開發者都在 JavaScript 最初引入時編寫類似下面的代碼:

    var oCar = new Object;   
    oCar.color 
    = "blue";   
    oCar.doors 
    = 4;   
    oCar.mpg 
    = 25;   
    oCar.showColor 
    = function() {   
      alert(
    this.color);   
    }
    ;  
    TIY

    在上面的代碼中,創建對象 car。然后給它設置幾個屬性:它的顏色是藍色,有四個門,每加侖油可以跑 25 英里。最后一個屬性實際上是指向函數的指針,意味著該屬性是個方法。執行這段代碼后,就可以使用對象 car。

    不過這里有一個問題,就是可能需要創建多個 car 的實例。

    解決方案:工廠方式
    要解決該問題,開發者創造了能創建并返回特定類型的對象的工廠函數(factory function)。

    例如,函數 createCar() 可用于封裝前面列出的創建 car 對象的操作:

    function createCar() {   
      
    var oTempCar = new Object;   
      oTempCar.color 
    = "blue";   
      oTempCar.doors 
    = 4;   
      oTempCar.mpg 
    = 25;   
      oTempCar.showColor 
    = function() {   
        alert(
    this.color);   
      }
    ;   
      
    return oTempCar;   
    }
       
      
    var oCar1 = createCar();   
    var oCar2 = createCar(); 

    TIY

    在這里,第一個例子中的所有代碼都包含在 createCar() 函數中。此外,還有一行額外的代碼,返回 car 對象(oTempCar)作為函數值。調用此函數,將創建新對象,并賦予它所有必要的屬性,復制出一個我們在前面說明過的 car 對象。因此,通過這種方法,我們可以很容易地創建 car 對象的兩個版本(oCar1 和 oCar2),它們的屬性完全一樣。

    為函數傳遞參數
    我們還可以修改 createCar() 函數,給它傳遞各個屬性的默認值,而不是簡單地賦予屬性默認值:

    function createCar(sColor,iDoors,iMpg) {   
      
    var oTempCar = new Object;   
      oTempCar.color 
    = sColor;   
      oTempCar.doors 
    = iDoors;   
      oTempCar.mpg 
    = iMpg;   
      oTempCar.showColor 
    = function() {   
        alert(
    this.color);   
      }
    ;   
      
    return oTempCar;   
    }
       
      
    var oCar1 = createCar("red",4,23);   
    var oCar2 = createCar("blue",3,25);   
      
    oCar1.showColor();      
    //輸出 "red"   
    oCar2.showColor();      //輸出 "blue" 

    TIY

    給 createCar() 函數加上參數,即可為要創建的 car 對象的 color、doors 和 mpg 屬性賦值。這使兩個對象具有相同的屬性,卻有不同的屬性值。

    在工廠函數外定義對象的方法
    雖然 ECMAScript 越來越正式化,但創建對象的方法卻被置之不理,且其規范化至今還遭人反對。一部分是語義上的原因(它看起來不像使用帶有構造函數 new 運算符那么正規),一部分是功能上的原因。功能原因在于用這種方式必須創建對象的方法。前面的例子中,每次調用函數 createCar(),都要創建新函數 showColor(),意味著每個對象都有自己的 showColor() 版本。而事實上,每個對象都共享同一個函數。

    有些開發者在工廠函數外定義對象的方法,然后通過屬性指向該方法,從而避免這個問題:

    function showColor() {   
      alert(
    this.color);   
    }
       
      
    function createCar(sColor,iDoors,iMpg) {   
      
    var oTempCar = new Object;   
      oTempCar.color 
    = sColor;   
      oTempCar.doors 
    = iDoors;   
      oTempCar.mpg 
    = iMpg;   
      oTempCar.showColor 
    = showColor;   
      
    return oTempCar;   
    }
       
      
    var oCar1 = createCar("red",4,23);   
    var oCar2 = createCar("blue",3,25);   
      
    oCar1.showColor();      
    //輸出 "red"   
    oCar2.showColor();      //輸出 "blue" 

    TIY

    在上面這段重寫的代碼中,在函數 createCar() 之前定義了函數 showColor()。在 createCar() 內部,賦予對象一個指向已經存在的 showColor() 函數的指針。從功能上講,這樣解決了重復創建函數對象的問題;但是從語義上講,該函數不太像是對象的方法。

    所有這些問題都引發了開發者定義 的構造函數的出現。

    構造函數方式
    創建構造函數就像創建工廠函數一樣容易。第一步選擇類名,即構造函數的名字。根據慣例,這個名字的首字母大寫,以使它與首字母通常是小寫的變量名分開。除了這點不同,構造函數看起來很像工廠函數。請考慮下面的例子:

    function Car(sColor,iDoors,iMpg) {   
      
    this.color = sColor;   
      
    this.doors = iDoors;   
      
    this.mpg = iMpg;   
      
    this.showColor = function() {   
        alert(
    this.color);   
      }
    ;   
    }
       
      
    var oCar1 = new Car("red",4,23);   
    var oCar2 = new Car("blue",3,25);   
    TIY

    下面為您解釋上面的代碼與工廠方式的差別。首先在構造函數內沒有創建對象,而是使用 this 關鍵字。使用 new 運算符構造函數時,在執行第一行代碼前先創建一個對象,只有用 this 才能訪問該對象。然后可以直接賦予 this 屬性,默認情況下是構造函數的返回值(不必明確使用 return 運算符)。

    現在,用 new 運算符和類名 Car 創建對象,就更像 ECMAScript 中一般對象的創建方式了。

    你也許會問,這種方式在管理函數方面是否存在于前一種方式相同的問題呢?是的。

    就像工廠函數,構造函數會重復生成函數,為每個對象都創建獨立的函數版本。不過,與工廠函數相似,也可以用外部函數重寫構造函數,同樣地,這么做語義上無任何意義。這正是下面要講的原型方式的優勢所在。

    原型方式
    該方式利用了對象的 prototype 屬性,可以把它看成創建新對象所依賴的原型。

    這里,首先用空構造函數來設置類名。然后所有的屬性和方法都被直接賦予 prototype 屬性。我們重寫了前面的例子,代碼如下:

    function Car() {   
    }
       
      
    Car.prototype.color 
    = "blue";   
    Car.prototype.doors 
    = 4;   
    Car.prototype.mpg 
    = 25;   
    Car.prototype.showColor 
    = function() {   
      alert(
    this.color);   
    }
    ;   
      
    var oCar1 = new Car();   
    var oCar2 = new Car();   
    TIY

    在這段代碼中,首先定義構造函數(Car),其中無任何代碼。接下來的幾行代碼,通過給 Car 的 prototype 屬性添加屬性去定義 Car 對象的屬性。調用 new Car() 時,原型的所有屬性都被立即賦予要創建的對象,意味著所有 Car 實例存放的都是指向 showColor() 函數的指針。從語義上講,所有屬性看起來都屬于一個對象,因此解決了前面兩種方式存在的問題。

    此外,使用這種方式,還能用 instanceof 運算符檢查給定變量指向的對象的類型。因此,下面的代碼將輸出 TRUE:

    alert(oCar1 instanceof Car);    //輸出 "true"  

     

    原型方式的問題
    原型方式看起來是個不錯的解決方案。遺憾的是,它并不盡如人意。

    首先,這個構造函數沒有參數。使用原型方式,不能通過給構造函數傳遞參數來初始化屬性的值,因為 Car1 和 Car2 的 color 屬性都等于 "blue",doors 屬性都等于 4,mpg 屬性都等于 25。這意味著必須在對象創建后才能改變屬性的默認值,這點很令人討厭,但還沒完。真正的問題出現在屬性指向的是對象,而不是函數時。函數共享不會造成問題,但對象卻很少被多個實例共享。請思考下面的例子:

    function Car() {   
    }
       
      
    Car.prototype.color 
    = "blue";   
    Car.prototype.doors 
    = 4;   
    Car.prototype.mpg 
    = 25;   
    Car.prototype.drivers 
    = new Array("Mike","John");   
    Car.prototype.showColor 
    = function() {   
      alert(
    this.color);   
    }
    ;   
      
    var oCar1 = new Car();   
    var oCar2 = new Car();   
      
    oCar1.drivers.push(
    "Bill");   
      
    alert(oCar1.drivers);   
    //輸出 "Mike,John,Bill"   
    alert(oCar2.drivers);   //輸出 "Mike,John,Bill"   

    TIY

    上面的代碼中,屬性 drivers 是指向 Array 對象的指針,該數組中包含兩個名字 "Mike" 和 "John"。由于 drivers 是引用值,Car 的兩個實例都指向同一個數組。這意味著給 oCar1.drivers 添加值 "Bill",在 oCar2.drivers 中也能看到。輸出這兩個指針中的任何一個,結果都是顯示字符串 "Mike,John,Bill"。

    由于創建對象時有這么多問題,你一定會想,是否有種合理的創建對象的方法呢?答案是有,需要聯合使用構造函數和原型方式。

    混合的構造函數/原型方式
    聯合使用構造函數和原型方式,就可像用其他程序設計語言一樣創建對象。這種概念非常簡單,即用構造函數定義對象的所有非函數屬性,用原型方式定義對象的函數屬性(方法)。結果是,所有函數都只創建一次,而每個對象都具有自己的對象屬性實例。

    我們重寫了前面的例子,代碼如下:

    function Car(sColor,iDoors,iMpg) {   
      
    this.color = sColor;   
      
    this.doors = iDoors;   
      
    this.mpg = iMpg;   
      
    this.drivers = new Array("Mike","John");   
    }
       
      
    Car.prototype.showColor 
    = function() {   
      alert(
    this.color);   
    }
    ;   
      
    var oCar1 = new Car("red",4,23);   
    var oCar2 = new Car("blue",3,25);   
      
    oCar1.drivers.push(
    "Bill");   
      
    alert(oCar1.drivers);   
    //輸出 "Mike,John,Bill"   
    alert(oCar2.drivers);   //輸出 "Mike,John" 

    TIY

    現在就更像創建一般對象了。所有的非函數屬性都在構造函數中創建,意味著又能夠用構造函數的參數賦予屬性默認值了。因為只創建 showColor() 函數的一個實例,所以沒有內存浪費。此外,給 oCar1 的 drivers 數組添加 "Bill" 值,不會影響到 oCar2 的數組,所以輸出這些數組的值時,oCar1.drivers 顯示的是 "Mike,John,Bill",而 oCar2.drivers 顯示的是 "Mike,John"。因為使用了原型方式,所以仍然能利用 instanceof 運算符來判斷對象的類型。

    這種方式是 ECMAScript 采用的主要方式,它具有其他方式的特性,卻沒有他們的副作用。不過,有些開發者仍覺得這種方法不夠完美。

    動態原型方法
    對于習慣使用其他語言的開發者來說,使用混合的構造函數/原型方式感覺不那么和諧。畢竟,定義類時,大多數面向對象語言都對屬性和方法進行了視覺上的封裝。請考慮下面的 Java 類:

    class Car {   
      
    public String color = "blue";   
      
    public int doors = 4;   
      
    public int mpg = 25;   
      
      
    public Car(String color, int doors, int mpg) {   
        
    this.color = color;   
        
    this.doors = doors;   
        
    this.mpg = mpg;   
      }
       
         
      
    public void showColor() {   
        System.out.println(color);   
      }
       
    }
       

    Java 很好地打包了 Car 類的所有屬性和方法,因此看見這段代碼就知道它要實現什么功能,它定義了一個對象的信息。批評混合的構造函數/原型方式的人認為,在構造函數內部找屬性,在其外部找方法的做法不合邏輯。因此,他們設計了動態原型方法,以提供更友好的編碼風格。

    動態原型方法的基本想法與混合的構造函數/原型方式相同,即在構造函數內定義非函數屬性,而函數屬性則利用原型屬性定義。唯一的區別是賦予對象方法的位置。下面是用動態原型方法重寫的 Car 類:

    function Car(sColor,iDoors,iMpg) {   
      
    this.color = sColor;   
      
    this.doors = iDoors;   
      
    this.mpg = iMpg;   
      
    this.drivers = new Array("Mike","John");   
         
      
    if (typeof Car._initialized == "undefined"{   
        Car.prototype.showColor 
    = function() {   
          alert(
    this.color);   
        }
    ;   
           
        Car._initialized 
    = true;   
      }
       
    }
       

    TIY

    直到檢查 typeof Car._initialized 是否等于 "undefined" 之前,這個構造函數都未發生變化。這行代碼是動態原型方法中最重要的部分。如果這個值未定義,構造函數將用原型方式繼續定義對象的方法,然后把 Car._initialized 設置為 true。如果這個值定義了(它的值為 true 時,typeof 的值為 Boolean),那么就不再創建該方法。簡而言之,該方法使用標志(_initialized)來判斷是否已給原型賦予了任何方法。該方法只創建并賦值一次,傳統的 OOP 開發者會高興地發現,這段代碼看起來更像其他語言中的類定義了。

    混合工廠方式
    這種方式通常是在不能應用前一種方式時的變通方法。它的目的是創建假構造函數,只返回另一種對象的新實例。

    這段代碼看起來與工廠函數非常相似:

    function Car() {   
      
    var oTempCar = new Object;   
      oTempCar.color 
    = "blue";   
      oTempCar.doors 
    = 4;   
      oTempCar.mpg 
    = 25;   
      oTempCar.showColor 
    = function() {   
        alert(
    this.color);   
      }
    ;   
      
      
    return oTempCar;   
    }
       
    TIY

    與經典方式不同,這種方式使用 new 運算符,使它看起來像真正的構造函數:

    var car = new Car();   

    由于在 Car() 構造函數內部調用了 new 運算符,所以將忽略第二個 new 運算符(位于構造函數之外),在構造函數內部創建的對象被傳遞回變量 car。

    這種方式在對象方法的內部管理方面與經典方式有著相同的問題。強烈建議:除非萬不得已,還是避免使用這種方式。

    采用哪種方式
    如前所述,目前使用最廣泛的是混合的構造函數/原型方式。此外,動態原始方法也很流行,在功能上與構造函數/原型方式等價。可以采用這兩種方式中的任何一種。不過不要單獨使用經典的構造函數或原型方式,因為這樣會給代碼引入問題。

    實例
    對象令人感興趣的一點是用它們解決問題的方式。ECMAScript 中最常見的一個問題是字符串連接的性能。與其他語言類似,ECMAScript 的字符串是不可變的,即它們的值不能改變。請考慮下面的代碼:

    var str = "hello ";   
    str 
    += "world";   

    實際上,這段代碼在幕后執行的步驟如下:

    創建存儲 "hello " 的字符串。
    創建存儲 "world" 的字符串。
    創建存儲連接結果的字符串。
    把 str 的當前內容復制到結果中。
    把 "world" 復制到結果中。
    更新 str,使它指向結果。
    每次完成字符串連接都會執行步驟 2 到 6,使得這種操作非常消耗資源。如果重復這一過程幾百次,甚至幾千次,就會造成性能問題。解決方法是用 Array 對象存儲字符串,然后用 join() 方法(參數是空字符串)創建最后的字符串。想象用下面的代碼代替前面的代碼:

    var arr = new Array();   
    arr[
    0= "hello ";   
    arr[
    1= "world";   
    var str = arr.join("");   

    這樣,無論數組中引入多少字符串都不成問題,因為只在調用 join() 方法時才會發生連接操作。此時,執行的步驟如下:

    創建存儲結果的字符串
    把每個字符串復制到結果中的合適位置
    雖然這種解決方案很好,但還有更好的方法。問題是,這段代碼不能確切反映出它的意圖。要使它更容易理解,可以用 StringBuffer 類打包該功能:

    function StringBuffer () {   
      
    this._strings_ = new Array();   
    }
       
      
    StringBuffer.prototype.append 
    = function(str) {   
      
    this._strings_.push(str);   
    }
    ;   
      
    StringBuffer.prototype.toString 
    = function() {   
      
    return this._strings_.join("");   
    }
    ;   

    這段代碼首先要注意的是 strings 屬性,本意是私有屬性。它只有兩個方法,即 append() 和 toString() 方法。append() 方法有一個參數,它把該參數附加到字符串數組中,toString() 方法調用數組的 join 方法,返回真正連接成的字符串。要用 StringBuffer 對象連接一組字符串,可以用下面的代碼:
    var buffer = new StringBuffer ();   
    buffer.append(
    "hello ");   
    buffer.append(
    "world");   
    var result = buffer.toString();   

    TIY

    可用下面的代碼測試 StringBuffer 對象和傳統的字符串連接方法的性能:

    var d1 = new Date();   
    var str = "";   
    for (var i=0; i < 10000; i++{   
        str 
    += "text";   
    }
       
    var d2 = new Date();   
      
    document.write(
    "Concatenation with plus: "  
     
    + (d2.getTime() - d1.getTime()) + " milliseconds");   
      
    var buffer = new StringBuffer();   
    d1 
    = new Date();   
    for (var i=0; i < 10000; i++{   
        buffer.append(
    "text");   
    }
       
    var result = buffer.toString();   
    d2 
    = new Date();   
      
    document.write(
    "<br />Concatenation with StringBuffer: "  
     
    + (d2.getTime() - d1.getTime()) + " milliseconds");   

    TIY
    這段代碼對字符串連接進行兩個測試,第一個使用加號,第二個使用 StringBuffer 類。每個操作都連接 10000 個字符串。日期值 d1 和 d2 用于判斷完成操作需要的時間。請注意,創建 Date 對象時,如果沒有參數,賦予對象的是當前的日期和時間。要計算連接操作歷經多少時間,把日期的毫秒表示(用 getTime() 方法的返回值)相減即可。這是衡量 JavaScript 性能的常見方法。該測試的結果應該說明使用 StringBuffer 類比使用加號節省了 50% - 66% 的時間。


    原帖地址:http://www.javaeye.com/topic/558037
    posted on 2010-09-03 15:18 李 明 閱讀(232) 評論(0)  編輯  收藏 所屬分類: JavaScript

    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 精品一区二区三区无码免费直播| 免费人成动漫在线播放r18| 国产成人亚洲午夜电影| a毛片在线免费观看| 最新猫咪www免费人成| 亚洲中文字幕无码不卡电影| 亚洲福利电影一区二区?| 色www免费视频| 蜜臀98精品国产免费观看| 免费观看国产小粉嫩喷水| 久久精品国产亚洲AV嫖农村妇女| 国产精品亚洲lv粉色| 最近免费中文字幕大全高清大全1 最近免费中文字幕mv在线电影 | 四虎国产精品免费永久在线| 在线观看特色大片免费视频| 国产亚洲色婷婷久久99精品91| 亚洲不卡视频在线观看| 四虎国产精品免费永久在线| 国产成人精品高清免费| 久久精品亚洲一区二区三区浴池| 美女被羞羞网站免费下载| www视频免费看| 亚洲日产无码中文字幕| 亚洲变态另类一区二区三区| 午夜精品免费在线观看| 国产国拍亚洲精品福利| 亚洲日韩久久综合中文字幕| 免费国产污网站在线观看15| 亚洲乱码中文字幕手机在线 | 亚洲精品福利在线观看| 国产高潮流白浆喷水免费A片 | 成年性午夜免费视频网站不卡 | 亚洲国产精品无码中文字| 理论亚洲区美一区二区三区| 国产精品久久久久久久久免费| 亚洲精品乱码久久久久久自慰| 日本亚洲欧美色视频在线播放| 麻豆视频免费观看| 亚洲AV无码国产丝袜在线观看| 四虎成人精品国产永久免费无码 | 一区二区三区亚洲视频|