太陽雨

          痛并快樂著

          BlogJava 首頁 新隨筆 聯系 聚合 管理
            67 Posts :: 3 Stories :: 33 Comments :: 0 Trackbacks

          還是《Professional JavaScript for Web Developers》。
          JavaScript也可以對象繼承?當我看到這一章第一個反應便是這個,以前從來沒有想過的,呵呵。
          JS實現繼承有如下幾種辦法:

          1. 對象冒充

          function ClassA(sColor) {
            this.color = sColor;
            this.sayColor = function() {
              alert(this.color);
            };
          }
          function ClassB(sColor, sName) {
            this.newMethod = ClassA;
            this.newMethod(sColor);
            delete this.newMethod;
            this.name = sName;
            this.sayName = function() {
              alert(this.name);
            };

          }
          var objA = new ClassA("red");
          var objB = new ClassB("blue", "Nicholas");
          objA.sayColor();  //outputs "red"
          objB.sayColor();  //outputs "blue"
          objB.sayName();  //outputs "Nicholas"

          呵呵,是不是很有趣。注意黃色代碼,所有新的屬性和新的方法必須在刪除了newMethod的代碼行后定義。否則,可能會覆蓋超類的相關屬性和方法。
          然后。。。用這個方法,還可以實現多重繼承,哈哈哈

          function ClassZ() {
            this.newMethod = ClassX;
            this.newMethod();
            delete this.newMethod;
            this.newMethod = ClassY;
            this.newMethod();
            delete this.newMethod;
          }

          不過這里有個小弊端,就是如果ClassX和ClassY有同名的屬性和方法的話,ClassY具有優先級,使用時要注意點,呵呵。

          2. call()方法

          先看看call()方法的使用:

          function sayColor(sPrefix, sSuffix) {
            alert(sPrefix + this.color + sSuffix);
          };
          var obj = new Object();
          obj.color = "red";
          sayColor.call(obj, "The color is ", ", a very nice color indeed.");

          這個例子中,sayColor雖然在對象外定義,即使他不屬于任何對象,也可以引用關鍵字this。調用call()方法時,第一個參數是obj,說明應該賦予sayColor()函數中的參數的this關鍵字值是obj,第二個和第三個參數就是sayColor()函數本身的參數sPrefix和sSuffix
          要與冒充對象方法一起使用該方法,只需要將前三行的賦值、調用和刪除代碼替換即可:

          function ClassA(sColor) {
            this.color = sColor;
            this.sayColor = function() {
              alert(this.color);
            };
          }
          function ClassB(sColor, sName) {
            //this.newMethod = ClassA;
            //this.newMethod(sColor);
            //delete this.newMethod;
            ClassA.call(this, sColor);

            this.name = sName;
            this.sayName = function() {
              alert(this.name);
            };
          }
          var objA = new ClassA("red");
          var objB = new ClassB("blue", "Nicholas");
          objA.sayColor();  //outputs "red"
          objB.sayColor();  //outputs "blue"
          objB.sayName();  //outputs "Nicholas"

          3. apply()方法

          apply()方法和call()方法很相似,唯一不同的就是將call()方法后面帶的多個參數存入數組再進行傳遞:

          function sayColor(sPrefix, sSuffix) {
            alert(sPrefix + this.color + sSuffix);
          };
          var obj = new Object();
          obj.color = "red";
          sayColor.apply(obj, new Array("The color is ", ", a very nice color indeed."));

          自然,很容易得出用apply()方法實現繼承的代碼:

          function ClassA(sColor) {
            this.color = sColor;
            this.sayColor = function() {
              alert(this.color);
            };
          }
          function ClassB(sColor, sName) {
            //this.newMethod = ClassA;
            //this.newMethod(sColor);
            //delete this.newMethod;
            ClassA.apply(this, new Array(sColor));

            this.name = sName;
            this.sayName = function() {
              alert(this.name);
            };
          }
          var objA = new ClassA("red");
          var objB = new ClassB("blue", "Nicholas");
          objA.sayColor();  //outputs "red"
          objB.sayColor();  //outputs "blue"
          objB.sayName();  //outputs "Nicholas"

          其中,如果超類參數順序與子類相同,圖中黃色區域可以這么寫:

          ClassA.apply(this, arguments);

          4. 原型鏈

          function ClassA() {
          }
          ClassA.prototype.color = "red";
          ClassA.prototype.sayColor = function() {
            alert(this.color);
          };
          function ClassB() {
          }
          ClassB.prototype = new ClassA();
          ClassB.prototype.name = "Nichloas";
          ClassB.prototype.sayName = function() {
            alert(this.name);
          }


          這個。。黃色那一句還是比較神奇的,呵呵。
          不過要注意,調用ClassA的構造函數時,沒有給它傳遞參數,這在原型鏈中是標準做法,要確保構造函數沒有任何參數!
          同時要注意上面的代碼,和對象冒充類似,子類的所有的屬性和方法都必須出現在prototype屬性被賦值后,因為在它之前賦值的所有方法都會被刪除!
          原型鏈的好處在于可以使用類似如下代碼檢測:

          var objB = new ClassB();
          alert(objB instanceof ClassA)  //outputs "true"
          alert(objB instance of ClassB) //outputs "true"

          而它的壞處在于不能多重繼承,不過用慣Java的人應該比較習慣吧,呵呵。

          5. 混合方式

          總結以上幾種方式,對象冒充的問題是必須使用構造函數方式,這不是最好的選擇(參考我的另一片讀書筆記《讀書筆記之JavaScript的類編寫方法》)。但如果使用原型鏈,又無法使用帶參數的構造函數了。那么混合模式就是解決這兩個問題的最好答案了,呵呵:

          function ClassA(sColor) {
            this.color = sColor;
          }
          ClassA.prototype.sayColor = function() {
            alert(this.color);
          };
          function ClassB(sColor, sName) {
            ClassA.call(this, sColor);
            this.name = sName;
          }
          ClassB.prototype = new ClassA();
          ClassB.prototype.sayName = function() {
            alert(this.name);
          };

          這種方式是推薦使用的,呵呵。

          最后還是那句話,以上源代碼均來自Nicholas C. Zakas的《Professional JavaScript for Web Developers》

          posted on 2009-11-06 01:51 小蟲旺福 閱讀(210) 評論(0)  編輯  收藏 所屬分類: Javascript相關
          主站蜘蛛池模板: 天镇县| 明溪县| 登封市| 竹北市| 游戏| 新蔡县| 涞水县| 黄骅市| 大姚县| 五峰| 兴和县| 邯郸县| 平陆县| 哈尔滨市| 石狮市| 伊春市| 阳高县| 屏东县| 大新县| 临泉县| 阳泉市| 青川县| 宜城市| 四平市| 武功县| 宜黄县| 互助| 云阳县| 滦平县| 舞钢市| 民乐县| 鹤壁市| 综艺| 高安市| 成安县| 乌拉特前旗| 汝州市| 布尔津县| 金华市| 勃利县| 新余市|