<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Javascript OOP框架YOOP重構實踐(上)

      大家好!今天跟大家一起分享我的OOP框架YOOP重構實踐,希望能與大家一起共同學習、共同進步。

      本文展示了我對沒有編寫測試的YOOP原始版本的重構過程。通過該重構,力圖將一個雜亂無章的遺留代碼重構為有良好測試的、結構良好、可讀性較強的高質量代碼。

      在本次重構中,我不但會對代碼結構進行重構,還會改變部分行為(如將“抽象類要檢查是否實現了接口成員和父類的抽象方法”修改為“抽象類不檢查是否實現了接口成員和父類的抽象方法”;將“抽象類、類只能繼承1個接口”修改為“可以繼承多個接口”等等)。改變行為時,必須先添加或者修改測試,然后才能小步地改變行為。

      原始版本

      (function () {
      
          /************************************************** String對象擴展 ***********************************************************
          
          擴展方法:
          contain
          containIgnoreCase
          trim
      
          */
          if (!String.prototype.contain) {
              String.prototype.contain = function (str) {
                  /* 使用RegExp對象來構造動態匹配。
                  注意!str是字符串,因此需要轉義!
      
                  由于JavaScript字符串中的“\”是一個轉義字符,因此,使用顯式構造函數創建RegExp實例對象時,應將原始正則表達式中的“\”用“\\”替換。例如,在代碼1.2中的兩條語句是等價的。
      
                  代碼1.2   轉義字符中的“\”:1.2.htm
      
                  <script language="javascript">
      
                  var re1 = new RegExp("\\d{5}");
      
                  var re2 = /\d{5}/;
      
                  alert("re1="+re1+"\nre2="+re2);
      
                  </script>
      
               
      
                  由于正則表達式模式文本中的轉義字符也是“\”,如果正則表達式中要匹配原義字符“\”,在正則表達式模式文本中要以“\\”來表示,當使用顯式構造函數的方式創建RegExp實例對象的時候,就需要使用“\\\\”來表示原義字符“\”。
      
                  var re = new RegExp(\\\\)。
      
                  */
                  var reg = new RegExp(str);
                  if (this.match(reg)) {  //用this指針指代本體
                      return true;
                  }
                  else {
                      return false;
                  }
              }
          }
      
          /*****************************************************************************************************************************/
      
      
          //當前是否處于創建類的階段。
          //放在自執行函數中,initializing就是自執行函數的內部變量,自執行函數的上下文結束后,外部就不能訪問initializing了。
          //不用var的話,就不是當前上下文的一個變量了,而是全局對象的一個屬性。這樣外部就能夠訪問了。
          var initializing = false;
          //    var count = 0;
      
      
          //獲得函數的參數數組
          function argumentNames(fn) {
              var names = fn.toString().match(/^[\s\(]*function[^(]*\(([^\)]*)\)/)[1].replace(/\s+/g, '').split(',');
              return names.length == 1 && !names[0] ? [] : names;
          };
      
          /* 深拷貝
          */
          function extendDeep(parent, child) {
              var i,
                      toStr = Object.prototype.toString,
                      sArr = "[object Array]",
                      sOb = "[object Object]",
                      type = "",
              child = child || {};
      
              for (i in parent) {
                  //if (parent.hasOwnProperty && parent.hasOwnProperty(i)) {
      
                  //                if (typeof parent[i] === 'object') {    //null === 'object'也為true!
      
                  type = toStr.call(parent[i]);
                  if (type === sArr || type === sOb) {    //如果為數組或object對象
                      child[i] = type === sArr ? [] : {};
                      extendDeep(parent[i], child[i]);
                  } else {
                      child[i] = parent[i];
                  }
              }
              //}
              return child;
          };
      
      
          //獲得函數名
          function getFunctionName(fn) {
              var name = "";
      
              if (!fn) {
                  return null;
              }
      
              name = fn.toString().match(/^.*function\s*([^\(]*)/);
              return name === null ? name : name[1];
          };
      
          //判斷是否為數組
          function isArray(val) {
              return Object.prototype.toString.call(val) === "[object Array]";
          };
      
          //檢查抽象類的公有方法+虛方法+抽象方法是否包含父類的抽象方法/屬性 或 接口方法/屬性。
          //不用hasOwnProperty判斷!否則就檢查不到是否包含了父類的抽象方法/屬性 或 接口方法/屬性。
          function check(parentClass, interface, children) {
              //        if (!parent || !interface || !children) {
              //            throw new Error("check - arguments error!");
              //        }
      
              var name = "";
      
              if (parentClass) {
                  //檢查是否實現了抽象方法/屬性
                  for (name in parentClass.prototype) {
                      if (parentClass.prototype.hasOwnProperty(name)) {
                          //                console.log(name);
                          if (name === "constructor") {
                              continue;
                          }
                          if (name.contain("Abstract_")) {
                              //抽象方法
                              if (typeof parentClass.prototype[name] === "function") {
                                  if (children[name.slice(9)] === undefined || typeof children[name.slice(9)] !== "function") {
                                      //                            var t = name.slice(9);
                                      throw new Error("Abstract method '" + name + "' must be overwrited!");
                                  }
                              }
                                  //抽象屬性
                              else {
                                  if (children[name.slice(9)] === undefined || typeof children[name.slice(9)] === "function") {
                                      //                            var t = name.slice(9);
                                      //                            var p = children[name.slice(9)];
                                      //                            var q = typeof children[name.slice(9)];
                                      throw new Error("Abstract attribute '" + name + "' must be overwrited!");
                                  }
                              }
                          }
                      }
                  }
              }
      
              if (!interface) {
                  return;
              }
      
              //檢查是否實現了接口方法/屬性
              for (name in interface.prototype) {
                  //                console.log(name);
                  if (name === "constructor") {
                      continue;
                  }
                  //                if (interface.prototype.hasOwnProperty(name)) {
                  //接口方法
                  if (typeof interface.prototype[name] === "function") {
                      //                    var t = name.slice(10);
                      //                    var m = children[name.slice(10)];
                      //                        console.log("t = " + t);
                      //                        console.log("m = " + m);
                      if (children[name.slice(10)] === undefined || typeof children[name.slice(10)] !== "function") {
                          throw new Error("Interface method '" + name + "' must be overwrited!");
                      }
                  }
                      //接口屬性
                  else {
                      //                    var t = name.slice(10);
                      //                    var m = children[name.slice(10)];
                      //                        console.log("t = " + t);
                      //                        console.log("m = " + m);
                      if (children[name.slice(10)] === undefined || typeof children[name.slice(10)] === "function") {
                          throw new Error("Interface attribute '" + name + "' must be overwrited!");
                      }
                  }
                  //                }
              }
          };
      
          //檢查抽象成員
          function addAbstract(abstract, currentClass, temp) {
              var name = "";
      
              for (name in abstract) {
                  if (abstract.hasOwnProperty(name)) {
                      //                if (typeof abstract[name] !== "function") {
                      //                    throw new Error("Virtual attribute is not allowed!");
                      //                }
                      //                else {
                      //抽象方法前面加"Abstract_"前綴
                      currentClass.prototype["Abstract_" + name] = abstract[name];
                      //                currentClass.prototype[name] = abstract[name];
      
                      temp[name] = abstract[name];    //加入temp
                      //                }
                  }
              }
          };
      
          //檢查虛方法(不能為虛屬性)
          function addVirtual(virtual, currentClass, temp) {
              var name = "";
      
              for (name in virtual) {
                  if (virtual.hasOwnProperty(name)) {
                      if (typeof virtual[name] !== "function") {
                          throw new Error("Virtual attribute is not allowed!");
                      }
                      else {
                          currentClass.prototype[name] = virtual[name];
      
                          temp[name] = virtual[name];    //加入temp
                      }
                  }
              }
          };
      
          //加入密封方法。
          //沒有實現檢查子類是否重寫了父類的密封方法,只是定義了一個規范。
          function addSealed(sealed, currentClass, temp) {
              var name = "";
      
              for (name in sealed) {
                  if (sealed.hasOwnProperty(name)) {
                      currentClass.prototype[name] = sealed[name];
      
                      temp[name] = sealed[name];    //加入temp
                  }
              }
          };
      
          //獲得在原型prototype中不存在同名的str。
          //如果有同名,則加上前綴"_"
          function getNoRepeatStrInPrototype(prototype, str) {
              var new_str = "";
      
              if (!prototype[str]) {
                  return str;
              }
      
              new_str = "_" + str;
              return getNoRepeatStrInPrototype(prototype, new_str);
          }
      
      
      
      
          //創建接口
          //接口可以繼承接口
          function MyInterface(_parent, _method, _attribute) {
              var i = 0, args = null;
      
              var parent = null,
                  method = null,
                  attribute = null;
      
              if (typeof _parent === "function") {
                  if (getFunctionName(_parent) !== "I") {
                      throw new Error("Interface must inherit interface!");
                  }
                  else {
                      parent = _parent;
      
                      //形如“MyInterface(Parent, "A", "B", "GetName");”
                      if (_method && !isArray(_method)) {
                          method = Array.prototype.slice.call(arguments, 1);
                          attribute = null;
                      }
                          //形如“MyInterface(Parent, ["A", "B", "GetName"], ["a", "c"]);”
                      else {
                          method = _method;
                          attribute = _attribute;
                      }
                  }
                  //            console.log(parent.toString());
              }
              else {
                  parent = null;
                  //形如“MyInterface("A", "B", "GetName");”
                  if (_method && !isArray(_method)) {
                      method = arguments
                      attribute = null;
                  }
                      //形如“MyInterface(["A", "B", "GetName"], ["a", "c"]);”
                  else {
                      method = arguments[0];
                      attribute = arguments[1];
                  }
              }
      
              function I() {
              }
      
              // 如果此接口需要從其它接口擴展
              if (parent) {
                  I.prototype = new parent();
                  I.prototype.constructor = I;
              }
      
              //        console.log("method = " + method);
              //        console.log("attribute = " + attribute);
      
      
              //        //形如“MyInterface(["A", "B", "GetName"], ["a", "c"]);”
              //        if (isArray(method)) {
      
              //方法
              for (i = 0; i < method.length; i++) {
                  //加上前綴“Interface_”
                  I.prototype["Interface_" + method[i]] = function () {
                      throw new Error("This method must be overwrited!");
                  };
              }
              //屬性
              if (attribute) {
                  if (!isArray(attribute)) {
                      throw new Error("Attribute must be array!");
                  }
                  else {
                      for (i = 0; i < attribute.length; i++) {
                          //加上前綴“Interface_”
                          I.prototype["Interface_" + attribute[i]] = 0;
                      }
                  }
              }
              //        }
              //        //形如“MyInterface("A", "B", "GetName");”
              //        else {
              //            args = Array.prototype.slice.call(arguments, 1);
              //            //方法
              //            for (i = 0; i < args.length; i++) {
              //                I.prototype[args[i]] = function () {
              //                    throw new Error("This method must be overwrited!");
              //                };
              //            }
              //        }
      
              return I;
          };
      
      
      
          //創建抽象類
          //抽象類能夠繼承接口、抽象類以及實體類,但此處約定抽象類只能繼承接口和抽象類,不能繼承實體類!
          //(這樣方便判斷抽象類是否包含全部的父類(接口/抽象類)成員)
          function MyAbstract(_parent, _prop) {
              var Static = null;
              var k = null, name = null, temp = {},
                  virtual = {};
      
              //        if (arguments.length > 1) {
              //            throw new Error("AbstractClass can't inherit other classes!");
              //        }
      
              var abstractClass = null,
                      interface = null,
                  prop = null;
      
              //原型恢復標志,用于防止第一次創建實例時恢復原型
              var mark_resume = false;
      
      
              //取出父類、接口
              if (arguments.length === 1) {
                  prop = arguments[0];
                  //            parent = null;
                  abstractClass = null;
                  interface = null;
              }
                  //_parent為{Class: xx, Interface: xx}
              else if (typeof _parent === "object") {
      
                  if (!_parent.Class && !_parent.Interface) {
                      throw new Error("Please add AbstractClass or Interface!");
                  }
                  if (getFunctionName(_parent.Class) === "F" || getFunctionName(_parent.Interface) === "F") {
                      throw new Error("AbstractClass here can't inherit parentClass which is created by MyClass function!");
                  }
      
                  abstractClass = _parent.Class;
                  interface = _parent.Interface;
      
                  prop = _prop;
              }
                  //_parent直接為xx,就表示父類為抽象類
              else if (typeof _parent === "function") {
                  if (getFunctionName(_parent) === "F") {
                      throw new Error("AbstractClass here can't inherit parentClass which is created by MyClass function!");
                  }
      
                  abstractClass = _parent;
                  interface = null;
      
                  prop = _prop;
              }
              else {
                  throw new Error("arguments is not allowed!");
              }
      
      
              Static = prop.Static ? prop.Static : null;
      
      
              // 本次調用所創建的類(構造函數)
              function A() {
                  //            // 如果抽象父類存在,則實例對象的baseClass指向父類的原型
                  //            // 這就提供了在實例對象中調用父類方法的途徑
                  //            if (abstractClass) {
                  //                this.baseClass = abstractClass.prototype;
                  //            }
      
                  ////防止第一次創建實例時恢復原型
                  //if (mark_resume) {
                  //    //還原原型
                  //    extendDeep(A.prototype.backUp_prototype, A.prototype);
                  //}
                  //else {
                  //    mark_resume = true;
                  //}
      
              }
      
              // 如果此接口需要從其它接口擴展
              if (abstractClass) {
                  //            //刪除父類的私有成員,保留本類的私有成員
                  //            for (name in abstractClass.prototype) {
                  //                if (abstractClass.prototype.hasOwnProperty(name)) {
                  //                    //私有成員以“_”開頭,可能有多個“_”(多層繼承)
                  //                    if (!name.match(/^_+/)) {
                  //                        //                                                delete parentClass.prototype[name];
                  //                        A.prototype[name] = abstractClass.prototype[name];
                  //                    }
                  //                }
                  //            }
      
                  //A.prototype = new abstractClass();
                  A.prototype = extendDeep(abstractClass.prototype);
      
                  A.prototype.constructor = A;
      
                  // 如果父類存在,則實例對象的baseClass指向父類的原型。
                  // 這就提供了在實例對象中調用父類方法的途徑。
                  //baseClass的方法是指向abstractClass的,不是指向F(子類)的!
      
                  A.prototype[getNoRepeatStrInPrototype(abstractClass.prototype, "baseClass")] = abstractClass.prototype;
                  //A.prototype.baseClass = abstractClass.prototype;
              }
      
              //加入構造函數
              //抽象類本身因為不能實例化,所以不調用構造函數。
              //抽象類中的構造函數供子類構造函數中調用。
              if (prop.Init) {
                  if (abstractClass) {
                      A.prototype.Init = function (name) {
                          return function () {
                              //此處不用創建閉包了!因為外面已經創建了閉包,name已經被保存了!
                              this.base = function () {
                                  //這個寫法也可以!為什么不用apply修正this也行??!
                                  //parentClass.prototype[name](); 
      
                                  //此處的arguments為base方法傳入的形參
                                  //注意!要加上“return”,這樣才能返回parentClass.prototype[name]的返回值
                                  return abstractClass.prototype[name].apply(abstractClass.prototype, arguments);
                              };
                              //指向子類,可以用于模版模式
                              this.baseToSubClass = abstractClass.prototype[name];
      
                              //執行fn并返回執行的結果
                              //此處的arguments為F.prototype[name]方法傳入的形參。
                              return prop[name].apply(this, arguments);
                          };
      
                      }("Init");
                  }
                  else {
                      A.prototype.Init = prop.Init;
                  }
              }
      
              if (prop.Private) {
                  //私有屬性/方法直接覆蓋
                  for (name in prop.Private) {
                      if (prop.Private.hasOwnProperty(name)) {
                          A.prototype[name] = prop.Private[name];
                      }
                  }
              }
      
              if (prop.Public) {
                  for (name in prop.Public) {
                      if (prop.Public.hasOwnProperty(name)) {
                          //檢查抽象成員,抽象成員放到Public或Protected中
                          if (name === "Abstract") {
                              addAbstract(prop["Public"][name], A, temp);
                              continue;
                          }
                          //檢查虛方法,虛方法放到Public或Protected中
                          if (name === "Virtual") {
                              addVirtual(prop["Public"][name], A, temp);
                              continue;
                          }
                          //密封的方法(不允許子類重寫)
                          if (name === "Sealed") {
                              addSealed(prop["Public"][name], A, temp);
                              continue;
                          }
      
                          if (abstractClass &&
                  typeof prop.Public[name] === "function" &&
                  typeof A.prototype[name] === "function") {
                              A.prototype[name] = function (name) {
                                  return function () {
                                      //此處不用創建閉包了!因為外面已經創建了閉包,name已經被保存了!
                                      this.base = function () {
                                          //這個寫法也可以!為什么不用apply修正this也行??!
                                          //parentClass.prototype[name](); 
      
                                          //此處的arguments為base方法傳入的形參
                                          //注意!要加上“return”,這樣才能返回parentClass.prototype[name]的返回值
                                          return abstractClass.prototype[name].apply(abstractClass.prototype, arguments);
                                      };
                                      //指向子類,可以用于模版模式
                                      this.baseToSubClass = abstractClass.prototype[name];
      
                                      //執行fn并返回執行的結果
                                      //此處的arguments為F.prototype[name]方法傳入的形參。
                                      return prop.Public[name].apply(this, arguments);
                                  };
      
                              }(name);
                          }
                          else {
                              A.prototype[name] = prop.Public[name];
                          }
      
      
      
                          temp[name] = prop.Public[name];    //用于檢查是否包含父類的抽象方法/屬性 或 接口方法/屬性
                      }
                  }
              }
              //保護成員
              if (prop.Protected) {
                  for (name in prop.Protected) {
                      if (prop.Protected.hasOwnProperty(name)) {
                          //檢查抽象成員,抽象成員放到Public或Protected中
                          if (name === "Abstract") {
                              addAbstract(prop["Protected"][name], A, temp);
                              continue;
                          }
                          //檢查虛方法,虛方法放到Public或Protected中
                          if (name === "Virtual") {
                              addVirtual(prop["Protected"][name], A, temp);
                              continue;
                          }
                          //密封的方法(不允許子類重寫)
                          if (name === "Sealed") {
                              addSealed(prop["Protected"][name], A, temp);
                              continue;
                          }
                          A.prototype[name] = prop.Protected[name];
      
                      }
                  }
              }
      
      
      
      
      
              //        //虛方法(不能為虛屬性)
              //        if (prop.Virtual) {
              //            for (name in prop.Virtual) {
              //                if (prop.Virtual.hasOwnProperty(name)) {
              //                    if (typeof prop.Virtual[name] !== "function") {
              //                        throw new Error("Virtual attribute is not allowed!");
              //                    }
              //                    else {
              //                        //                        //虛方法前面加"Virtual_"前綴,在子類中要檢查虛方法
              //                        A.prototype[name] = prop.Virtual[name];
      
              //                        temp[name] = prop.Virtual[name];    //用于檢查是否包含父類的抽象方法/屬性 或 接口方法/屬性
              //                    }
              //                }
              //            }
              //        }
      
      
              //抽象類可以沒有抽象成員
              //        if (!prop.Abstract) {
              //            throw new Error("AbstractClass must have abstract methods!");
              //        }
      
              //放到外面的抽象成員,默認為公有抽象成員
              for (name in prop.Abstract) {
                  if (prop.Abstract.hasOwnProperty(name)) {
                      //                console.log();
                      //抽象方法前面加"Abstract_"前綴
                      A.prototype["Abstract_" + name] = prop.Abstract[name];
      
                      temp[name] = prop.Abstract[name];   //用于檢查是否包含父類的抽象方法/屬性 或 接口方法/屬性
                  }
              }
      
              //        //檢查抽象類的公有方法+虛方法+抽象方法是否包含父類的抽象方法/屬性 或 接口方法/屬性
              //檢查抽象類的公有方法+虛方法+抽象方法是否包含父類的接口方法/屬性
              check(null, interface, temp);
      
              //靜態屬性/方法賦值
              for (k in Static) {
                  A[k] = Static[k];
              }
      
              ////備份原型
              //A.prototype.backUp_prototype = extendDeep(A.prototype);
      
              return A;
          }
      
      
      
          //    //是否調用父類函數
          //    var base_flag = false;
      
          //創建普通類
          //父類_parent可以為{Class: xx, Interface: xx},或者直接為xx類
          function MyClass(_parent, _prop) {
              //        console.log("length = " + arguments.length);
              var Static = null;
              //                    Private = null,
              //            Public = null,
              //            Origin = null;
      
              var k = null, name = null;
      
              var parentClass = null, interface = null, prop = null, temp = {};
              //        var temp = null;
      
              //        //原型備份容器,用于創建實例時,恢復最初的原型(每次創建實例時,原型都保持不變)。
              //        var backUp_prototype = {};
      
              //原型恢復標志,用于防止第一次創建實例時恢復原型
              var mark_resume = false;
      
      
              //取出父類、接口
              if (arguments.length === 1) {
                  prop = arguments[0];
                  parentClass = null;
                  interface = null;
              }
                  //{Class: xx, Interface: xx}
              else if (typeof _parent === "object") {
                  //            if (parent.Class)
                  if (!_parent.Class && !_parent.Interface) {
                      throw new Error("Please add Class or Interface!");
                  }
      
                  parentClass = _parent.Class;
                  interface = _parent.Interface;
      
                  prop = _prop;
              }
                  //直接為xx類
              else if (typeof _parent === "function") {
                  parentClass = _parent;
                  interface = null;
                  //            parent = _parent;
                  //            interface = null;
      
                  prop = _prop;
              }
              else {
                  throw new Error("arguments is not allowed!");
              }
      
      
      
              //取出靜態屬性/方法、私有屬性/方法、公有屬性/方法
              //        Private = prop.Private;
      
              //        Public = prop.Public;
      
              Static = prop.Static ? prop.Static : null;
      
      
      
              //        //保存原始的私有屬性,用于創建實例時,重置私有屬性
              //        //        var Origin = {};
              //        //        Origin = Private
              //        Origin = operate.extendDeep(Private);
              //        YYC.Tool.extend.extend(Origin, Private);
      
      
              //        //訪問公共屬性/方法的入口,
              //        MyClass.Public = Public;
      
      
              // 本次調用所創建的類(構造函數)
              function F() {
                  //            console.log(mark_resume);
      
      
      
                  //防止第一次創建實例時恢復原型
                  if (mark_resume) {
                      //var t = F.prototype.backUp_prototype;
                      //var m = F.prototype;
      
                      //還原原型
                      //extendDeep(F.prototype.backUp_prototype, F.prototype);
                      extendDeep(F.backUp_prototype, F.prototype);
      
      
                      //F.prototype.backUp_prototype = extendDeep(F.prototype);
                  }
                  else {
                      mark_resume = true;
                  }
      
                  // 如果當前處于實例化類的階段,則調用Init原型函數
                  if (!initializing) {
                      //                console.log("F");
                      //                // 如果父類存在,則實例對象的baseClass指向父類的原型
                      //                // 這就提供了在實例對象中調用父類方法的途徑
                      //                if (parentClass) {
                      //                    this.baseClass = parentClass.prototype;
                      //                    //                    console.log(this.baseClass);
                      //                }
                      this.Init && this.Init.apply(this, arguments);
                  }
      
                  //            this.Public = Public;
      
                  //            console.log("F");
      
      
                  //            if (this.)
                  //            console.log(this._m);
                  //            delete this._m;
      
                  //            delete F.prototype._m;
                  //            delete F.prototype._a;
                  //            this._m = null;
                  //            this._a = null;
                  //            delete F.prototype._a;
      
      
      
                  /*不能刪除私有成員和保護成員!否則類的成員就不能調用到私有和保護的成員了(因為已經刪除了)!
                  對象的創建算法參考http://www.rzrgm.cn/TomXu/archive/2012/02/06/2330609.html
      
      
      
      
                  //刪除私有成員和保護成員,這樣外界就不能訪問私有和保護成員了!
                  for (name in this) {
                  if (name.search(/(^_)|(^P_)/) !== -1) {
                  delete F.prototype[name];
                  //                                                    this[name] = null;
                  }
                    
                  }
                  */
      
      
      
                  //            console.log(count);
                  //            count++;
      
                  //不使用MyClass.self!因為該屬性為靜態屬性,如果創建了該類后,又創建了類A,則MyClass.self會指向類A!
      
                  //            MyClass的靜態屬性self指向創建的類的實例,可以通過self來訪問實例的屬性和方法
                  //            MyClass.self = this;
      
      
      
      
      
                  //            Private.C();
      
                  //            for (name in Private) {
                  //                Private[name].call(this);
                  //            }
      
      
      
      
              }
      
      
      
      
              //        Private.C = Private.C.call(null, Public);
      
              //        Private.call(F, null);
      
              //                Private.M = (function (pub) {
              //                    return function () {
              //                        Private.M.call(null, arguments);
              //                    }
              //                }(Public));
      
      
              //        for (name in Private) {
              //            Private[name] = function () {
              //                //            console.log("1111111");
              //                return function () {
              //                    //                console.log("222222222");
              //                    return Private[name].call(this, arguments);
              //                }
      
              //            };
              //        }
      
      
      
              //        Private.C = function () {
              //            return function () {
              //                Private.C.call(F, arguments);
              //            }
              //        };
      
      
              // 如果此類需要從其它類擴展
              if (parentClass) {
      
                  initializing = true;
                  //F.prototype = new parentClass();
                  F.prototype = extendDeep(parentClass.prototype);
      
      
                  F.prototype.constructor = F;
      
                  //            for (name in parentClass.prototype) {
                  //                if (parentClass.prototype.hasOwnProperty(name)) {
                  //                    //私有成員不繼承
                  //                    if (!name.match(/^_/)) {
                  //                        F.prototype[name] = parentClass.prototype[name];
                  //                    }
                  //                }
                  //            }
      
                  //            //刪除父類的私有成員,保留本類的私有成員
                  //            for (name in parentClass.prototype) {
                  //                if (parentClass.prototype.hasOwnProperty(name)) {
                  //                    //私有成員以“_”開頭,可能有多個“_”(多層繼承)
                  //                    if (!name.match(/^_+/)) {
                  //                        //                                                delete parentClass.prototype[name];
                  //                        F.prototype[name] = parentClass.prototype[name];
                  //                    }
                  //                }
                  //            }
      
                  //            console.log(F.prototype.constructor);
      
      
                  // 如果父類存在,則實例對象的baseClass指向父類的原型。
                  // 這就提供了在實例對象中調用父類方法的途徑。
                  //baseClass的方法是指向parentClass的,不是指向F(子類)的!
                  //F.prototype.baseClass = parentClass.prototype;
      
      
                  F.prototype[getNoRepeatStrInPrototype(parentClass.prototype, "baseClass")] = parentClass.prototype;
      
                  initializing = false;
              }
      
              if (prop.Init) {
      
      
      
                  // 如果此類繼承自父類parent并且父類原型中存在同名函數name
                  if (parentClass &&
          typeof prop.Init === "function" &&
          typeof F.prototype.Init === "function") {
                      F.prototype.Init = function (name) {
                          return function () {
                              this.base = function () {
                                  return parentClass.prototype[name].apply(parentClass.prototype, arguments);
                              };
                              //指向子類,可以用于模版模式
                              this.baseToSubClass = parentClass.prototype[name];
                              //執行fn并返回執行的結果
                              //此處的arguments為F.prototype[name]方法傳入的形參。
                              return prop[name].apply(this, arguments);
                          };
      
                      }("Init");
                  }
                  else {
                      F.prototype.Init = prop.Init;
                  }
              }
      
      
              //        Private.call(this);
      
              //        if (parentClass && parentClass.prototype["JudgeDoubleHit"]) {
              //            console.log(parentClass.toString());
      
      
              if (parentClass) {
                  for (name in parentClass.prototype) {
                      if (parentClass.prototype.hasOwnProperty(name)) {
                          //如果不是抽象方法/保護方法/私有方法/接口成員,則加入到temp中。
                          //用于添加父類的密封方法(因為子類并沒有加入父類的密封方法)。
                          if (!name.match(/^Abstract_/) || !name.match(/^P_/) || !name.match(/^_/) || !name.match(/^Interface_/)) {
                              temp[name] = parentClass.prototype[name];
                          }
                      }
                  }
              }
      
      
      
      
      
              //        }
      
              //        if (this.baseClass.Protected) {
              //            if (this.baseClass.Protected.Sealed) {
      
              //                for (k in this.baseClass.Protected.Sealed) {
              //                    temp[k] = this.baseClass.Protected.Sealed[k];
              //                }
              //            }
              //        }
      
      
              if (prop.Private) {
                  //私有屬性/方法直接覆蓋
                  for (name in prop.Private) {
                      if (prop.Private.hasOwnProperty(name)) {
                          F.prototype[name] = prop.Private[name];
                      }
                  }
              }
      
              //        if (!prop.Public) {
              //            throw new Error("Class must have public methods!");
              //        }
              //        else {
      
              //        }
      
      
              //保護成員
              if (prop.Protected) {
                  for (name in prop.Protected) {
                      if (prop.Protected.hasOwnProperty(name)) {
                          //檢查虛方法,虛方法放到Public或Protected中
                          if (name === "Virtual") {
                              addVirtual(prop["Protected"][name], F, temp);
                              continue;
                          }
                          //密封的方法(不允許子類重寫)
                          if (name === "Sealed") {
                              addSealed(prop["Protected"][name], F, temp);
                              continue;
                          }
      
                          F.prototype[name] = prop.Protected[name];
      
                          //如果父類有保護抽象成員,此處檢查子類的保護成員是否實現了父類的保護抽象成員
                          temp[name] = prop.Protected[name];
                      }
                  }
              }
      
              //        //虛方法(不能為虛屬性)
              //        if (prop.Virtual) {
              //            for (name in prop.Virtual) {
              //                if (prop.Virtual.hasOwnProperty(name)) {
              //                    if (typeof prop.Virtual[name] !== "function") {
              //                        throw new Error("Virtual attribute is not allowed!");
              //                    }
              //                    else {
              //                        F.prototype[name] = prop.Virtual[name];
      
              //                        temp[name] = prop.Virtual[name];    //加入temp
              //                    }
              //                }
              //            }
              //        }
      
              if (prop.Abstract) {
                  throw new Error("Only abstractClass can have abstract methods!");
              }
      
      
      
              if (prop.Public) {
                  // 覆蓋父類的同名公有方法
                  for (name in prop.Public) {
                      //            console.log("for in name = " + name);
                      //            //私有屬性/方法不加入到原型中
                      //            if (name === "Private") {
                      ////                console.log("continue");
                      //                continue;
                      //            }
      
                      if (prop.Public.hasOwnProperty(name)) {
                          //檢查虛方法,虛方法放到Public或Protected中
                          if (name === "Virtual") {
                              addVirtual(prop["Public"][name], F, temp);
                              continue;
                          }
                          //密封的方法(不允許子類重寫)
                          if (name === "Sealed") {
                              addSealed(prop["Public"][name], F, temp);
                              continue;
                          }
                          //                    console.log("Public");
                          //                    console.log("name = " + name);
                          //                    console.log("prop.Public[name] = " + prop.Public[name]);
                          temp[name] = prop.Public[name];     //加入temp
      
                          // 如果此類繼承自父類parent并且父類原型中存在同名函數name
                          if (parentClass &&
                  typeof prop.Public[name] === "function" &&
                  typeof F.prototype[name] === "function") {
                              //                        console.log("parent!");
      
      
      
      
                              F.prototype[name] = function (name) {
                                  return function () {
                                      /*此處如果寫成“this.base = parentClass.prototype[name];”,則在使用this.base()調用父類同名方法時,
                                      父類同名方法的this指針是指向F的?。粗赶蜃宇悾皇侵赶蚋割悾。?  為什么????
                                      如:
                                      var Person = MyAbstract({
                                      Init: function (name) {
                                      this.name = name;
                                      },
                                      Public: {
                                      m: 1,
                                      getEmployeeID: function () {
                                      console.log(this.m);
                                      }
                                      }
                                      }
                                      });
      
      
                                      var Employee = MyClass({
                                      Init: function (name) {
                                      this.name = name;
                                      },
                                      Public: {
                                      m: 100,
                                      getEmployeeID: function () {
                                      this.baseClass.getEmployeeID();
                                      this.base();
                                      }
                                      }
                                      });
      
                                      var m = new Employee();
                                      m.getEmployeeID();    //輸出:1  100
      
                                      分析:
                                  
                                      this.baseClass.getEmployeeID()的this指向Person,而this.base()的this指向Employee!
      
                                      解決方案:
      
                                      用apply修正this.base()中的this,使其指向父類。
                                      */
      
      
                                      //                                if (!this.base) {
                                      //此處不用創建閉包了!因為外面已經創建了閉包,name已經被保存了!
                                      this.base = function () {
                                          //這個寫法也可以!為什么不用apply修正this也行??!
                                          //parentClass.prototype[name](); 
      
                                          //此處的arguments為base方法傳入的形參
                                          //注意!要加上“return”,這樣才能返回parentClass.prototype[name]的返回值
                                          return parentClass.prototype[name].apply(parentClass.prototype, arguments);
      
                                          //                                    this.baseClass.
                                      };
                                      //                                }
                                      //                                if (!this.baseToSubClass) {
                                      //指向子類,可以用于模版模式
                                      this.baseToSubClass = parentClass.prototype[name];
                                      //                                }
      
                                      //                                this.base = function () {
                                      //                                    //                                    console.log(base_flag);
      
                                      //                                    Private = {
                                      //                                    };
                                      ////                                    base_flag = true;
                                      //                                    return parent.prototype[name];
                                      //                                };
                                      //                            console.log("arg = " + arg);
      
                                      //執行fn并返回執行的結果
                                      //此處的arguments為F.prototype[name]方法傳入的形參。
                                      return prop.Public[name].apply(this, arguments);
                                  };
      
                              }(name);
      
                          }
                          else {
                              //                    console.log();
                              //公有屬性
                              if (typeof (prop.Public[name]) !== "function") {
                                  F.prototype[name] = prop.Public[name];
                              }
                                  //公有方法
                              else {
                                  /* 如果不傳入Public[name],而直接在自執行函數中調用Public[name],如
                                  F.prototype[name] = function () {
                                  return function () {
                                  prop.Public[name].apply(this, arguments);
                                  };
                                  } ();
      
                                  或者寫成:
                                  F.prototype[name] = function () {
                                  prop.Public[name].call(this, arguments);
                                  };
                              
                              
                                  這樣的話,在創建實例時調用方法時,都會執行MyClass中的最后一個函數!見下例
                              
                                  var Person = MyClass({
                                  Init: function (name) {
                                  this.name = name;
                                  },
                                  getName: function () {
                                  console.log("getName");
                                  },
                                  getEmployeeID: function ($private) {
                                  console.log("Person getEmployeeID");
                                  }
                                  });
                                  var m = new Person("name");     
                                  m.getName();    //第一種和第二種寫法此處會輸出:"Person getEmployeeID"
                      
      
                                  這樣執行的原因是:
      
                                  (引用自“深入理解JavaScript系列(16):閉包(Closures)”)
                                  同一個父上下文中創建的閉包是共用一個[[Scope]]屬性的。也就是說,
                                  某個閉包對其中[[Scope]]的變量做修改會影響到其他閉包對其變量的讀取。
                                  這就是說:所有的內部函數都共享同一個父作用域。
      
                                  也就是說,function里面的name都是共用父作用域中的name!所以此處F.prototype[name]被激活的時候,
                                  name都為最后一個值即"getEmployeeID"。
                                  所以F原型上的方法都指向"getEmployeeID"
      
                                  解決方案:
      
                                  創建一個閉包來保存name的值。
                                  */
                                  F.prototype[name] = function (name) {
                                      return function () {
                                          return prop.Public[name].apply(this, arguments);     //執行fn并返回執行的結果
                                      };
                                  }(name);
      
                              }
                          }
                      }
                  }
              }
      
      
      
      
              //檢查公有成員和虛函數是否實現了抽象方法/屬性 或 接口方法/屬性
              check(parentClass, interface, temp);
      
      
              //靜態屬性/方法賦值
              for (k in Static) {
                  F[k] = Static[k];
              }
      
      
      
              //備份原型
              //F.prototype.backUp_prototype = extendDeep(F.prototype);
              F.backUp_prototype = extendDeep(F.prototype);
      
      
              return F;
          };
      
          YYC.Pattern.namespace("Frame").MyInterface = MyInterface;
      
          YYC.Pattern.namespace("Frame").MyAbstract = MyAbstract;
      
          YYC.Pattern.namespace("Frame").MyClass = MyClass;
      }());
      View Code

      代碼分析

      我并不打算對代碼詳細說明,因為該文的重點在于展示重構的過程。因此我介紹下原始版本實現OOP的核心內容,具體請參考代碼。

      MyInterface為接口,MyAbstract為抽象類,MyClass為類。

      創建一個接口,可以這樣寫:

      var A = YYC.Frame.MyInterface("method1", "method2");

      調用“YYC.Frame.MyInterface”時,會調用MyInterface函數,該函數會把參數解析,把方法和屬性加上前綴“Interface_”,加入到內部函數I.prototype中,然后返回內部函數I。

      因此,A就具有了接口方法和接口屬性,但是我們不會直接使用接口(如創建A的實例,訪問接口方法),因為接口的方法和屬性(統稱為成員)并沒有實現,需要在繼承接口的類中實現。

      然后創建一個抽象類:

      var B = YYC.Frame.MyAbstract({
          Protected: {    //保護成員
              Abstract: { //保護抽象成員
              },
              Virtual: {  //保護虛方法
              },
              P_proA: true,   //保護屬性
              P_proM: function () { }    //保護方法
          },
          Public: {   //公有成員
              Abstract: { //公有抽象成員
              },
              Virtual: {  //公有虛方法
              },
              pubM: function () { },  //公有方法
              pubA: 0    //公有屬性
          },
          Private: {  //私有成員
              _priA: "",   //私有屬性
              _priM: function () { } //私有方法
          },
          Abstract: { //公有抽象成員
          },
          Virtual: {  //公有虛方法
          }
      });
      View Code

      調用“YYC.Frame.MyAbstract”時,會調用MyAbstract函數,該函數會把參數解析,將公有成員、私有成員、保護成員都加入到內部函數A.prototype中(約定私有成員、保護成員的命名規則,約定使用框架者遵守訪問權限)。

      抽象成員(Abstract:{}中的成員)先加上前綴“Abstract_”,然后加入到A.prototype中(子類根據前綴來區分判斷是否實現了父類的抽象成員)。

      然后創建一個類,繼承接口A和抽象類B:

      var C = YYC.Frame.MyClass({Interface: A, Class: B},{
          Init: function () { //構造函數
          },
          Protected: {    //保護成員
          },
          Public: {   
              Virtual: { 
              },
              method1: function () { }, 
              method2: function () { }
          },
          Private: {  //私有成員
              _priA: "",   //私有屬性
              _priM: function () { } //私有方法
          }
      });
      View Code

      調用“YYC.Frame.MyClass”時,會調用MyClass函數,該函數會把參數解析,將公有成員、私有成員、保護成員都加入到內部函數F.prototype中。

      構造函數Init在F的構造函數function F(){}中調用,從而在創建C的實例時,會調用構造函數Init。

      此處繼承了接口A和抽象類B,因此會先用深拷貝的方法來將A、B的成員加入到F.prototype中,然后判斷是否實現A的接口成員(根據“Interface_”前綴來判斷)、是否實現B的抽象成員(根據“Abstract_”前綴來判斷),如果沒有實現會拋出異常。

      為什么要用深拷貝來實現繼承

      //F.prototype = new parentClass();
      F.prototype = extendDeep(parentClass.prototype);
      

      此處繼承使用深拷貝來實現,原因是為了解決下面的問題:

      • 若父類Parent的屬性為引用類型(數組或對象)a,有兩個子類Sub1、Sub2。如果子類Sub1的實例s1對a進行修改或者sub調用修改a的方法,則子類Sub2的實例的a為修改過后的a!

      問題描述

      var Parent = YYC.Frame.MyClass({
          Private:{
              _a: []
          },
          Public: {
              add: function () {
                  this._a.push("a");
              }
          }
      });
      var Sub1 = YYC.Frame.MyClass(Parent, {});
      var Sub2 = YYC.Frame.MyClass(Parent, {});
      
      var t = new Sub1();
      t.add();
      console.log(t.a);        //["a"]
      var k = new Sub2();
      console.log(k.a);    //照理說應該為[],但實際上卻是["a"]!

      原因分析

      上例中的“t.add();”修改的是實例t的_a屬性,實例t的_a屬性與Parent.prototype._a指向同一個數組。因此修改實例t的_a就相當于修改了Parent.prototype._a。

      解決方案

      修改類繼承方式,改為通過深拷貝的方式拷貝父類原型的成員來實現繼承:

      F.prototype = extendDeep(parentClass.prototype);

      這樣實例t的_a屬性和Parent.protype._a就指向不同的數組了。

      為什么要重構

      原始版本對其它的庫有依賴(如依賴于namespace.js),有太多沒用或錯誤的注釋,混在一起的職責,過于龐大的函數,函數名、屬性名不能很好地體現職責,多層嵌套的條件式等等。另外,最大的問題是沒有對應的測試套件。

      開始重構

      編寫測試

      回到本次重構中來,要進行重構,首先需要堅固的測試作保證。我使用Jasmine作為Javascript的測試工具。建議大家先可以看下javascript單元測試,里面介紹了單元測試的工具,包括Jasmine。

      先編寫幾個主要的測試,測試是否解決了我之前發現的幾個問題。

      describe("oopFrame", function () {
          describe("測試Class", function () {
              describe("獲得公有成員", function () {
                  it("如果父類不存在,能夠正確獲得公有方法", function () {
                      var Class = YYC.Frame.MyClass({
                          Public: {
                              a: function () {
                                  this.b = 1;
                                  return 0;
                              }
                          }
                      });
      
                      var cla = new Class();
                      var result = cla.a();
      
                      expect(result).toEqual(0);
                      expect(cla.b).toEqual(1);
                  });
              });
          });
      
          describe("集成測試", function () {
              it("測試解決“若父類的屬性為引用類型(數組或對象)a,則如果子類的實例s1對a進行修改或者sub調用修改a的方法,則第二次創建實例s2的a為修改過后的a!”的問題", function () {
                  var Parent = YYC.Frame.MyAbstract({
                      Init: function () {
                          console.log("Parent Init!");
                      },
                      Public: {
                          a: [],
                      }
                  });
                  var Sub = YYC.Frame.MyClass(Parent, {
                      Init: function () {
                      },
                      Public: {
                      }
                  });
      
                  var t = new Sub();
                  t.a.push("a");
                  var m = new Sub();
      
                  expect(m.a).toEqual([]);
              });
              it("測試解決“若父類Parent的屬性為引用類型(數組或對象)a,有兩個子類Sub1、Sub2。如果子類Sub1的實例s1對a進行修改或者sub調用修改a的方法,則子類Sub2的實例的a為修改過后的a!”的問題", function () {
                  var Parent = YYC.Frame.MyAbstract({
                      Init: function () {
                          console.log("Parent Init!");
                      },
                      Public: {
                          a: [],
                          add: function () {
                              this.a.push("a");
                          }
                      }
                  });
                  var Sub1 = YYC.Frame.MyClass(Parent, {
                      Init: function () {
                      },
                      Public: {
                      }
                  });
                  var Sub2 = YYC.Frame.MyClass(Parent, {
                      Init: function () {
                      }
                  });
      
                  var t = new Sub1();
                  t.a.push("a");
                  var k = new Sub2();
      
                  expect(k.a).toEqual([]);
      
              });
              it("測試解決“若A1為抽象類,A2(抽象類)繼承于A1,B(類)繼承于A2,A1、A2、B都有同名方法a,A2和B在a方法中都通過this.baseClass調用父類同名方法。則如果B的實例b調用a方法,則A2、B的a方法中的this.baseClass均指向A2(照理說A2的this.baseClass應該指向A1)!”的問題", function () {
                  var A1 = YYC.Frame.MyAbstract({
                      Public: {
                          arr: [],
                          a: function () {
                              this.arr.push(1);
                          }
                      }
                  });
                  var A2 = YYC.Frame.MyAbstract(A1, {
                      Public: {
                          a: function () {
                              this.arr.push(2);
                              this.baseClass.a.call(this, null);
                          }
                      }
                  });
                  var B = YYC.Frame.MyClass(A2, {
                      Public: {
                          a: function () {
                              this.arr.push(3);
                              this._baseClass.a.call(this, null);
      
                              return this.arr;
                          }
                      }
                  });
                  var b = new B();
      
                  expect(b.a()).toEqual([3, 2, 1]);
              });
          });
      });
      View Code

      現在測試的覆蓋面還不全,有些代碼沒有測試到。不過我們已經構建了主要的測試,剩下的測試可以在后續的重構中逐漸加入。

      測試頁面

      <%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
      <!DOCTYPE HTML>
      <html>
      <head id="Head1" runat="server">
         <title>Jasmine Spec Runner</title>
        <link rel="stylesheet" type="text/css" href="<%=Url.Content("~/Scripts/jasmine/lib/jasmine-1.3.1/jasmine.css") %>" />
              <script src="<%=Url.Content("~/Scripts/jasmine/lib/jasmine-1.3.1/jasmine.js") %>"></script>
          <script src="<%=Url.Content("~/Scripts/jasmine/lib/jasmine-1.3.1/jasmine-html.js") %>"></script>
        <!-- include source files here... -->
          <script src="<%=Url.Content("~/Scripts/jquery-1.7.js")%>"></script>
          <script src="../../Scripts/myTool/pattern/createObject/namespace.js"></script>
          <script src="<%=Url.Content("~/Scripts/myTool/frame/YOOP.js")%>"></script>
        <!-- include spec files here... -->
          <script src="<%=Url.Content("~/Scripts/jasmine/spec/helper/specHelper.js")%>"></script>
          <script src="../../Scripts/jasmine/spec/frameSpec/YOOPSpec.js"></script>
      </head>
      <body>
      
      
        <script type="text/javascript">
            (function () {
                    var jasmineEnv = jasmine.getEnv();
                    jasmineEnv.updateInterval = 1000;
      
                    var htmlReporter = new jasmine.HtmlReporter();
      
                    jasmineEnv.addReporter(htmlReporter);
      
                    jasmineEnv.specFilter = function (spec) {
                        return htmlReporter.specFilter(spec);
                    };
                    function execJasmine() {
                        jasmineEnv.execute();
                    }
      
      
                    var currentWindowOnload = window.onload;
      
      
      
                    if (currentWindowOnload) {
                        currentWindowOnload();
                    }
                    execJasmine();
            })();
      </script>
      
      </body>
      </html>
      View Code

      在測試頁面中運行測試,通過全部測試。

      解除對其它庫的依賴

      現在該框架通過了測試,能夠正常工作。但是因為它采用命名空間模式,需要依賴于namespace.js庫。

      我想解除這個依賴,因此直接在框架中定義YYC命名空間,并且考慮到該框架的通用性較高,因此將其命名空間YYC.Frame更改為YYC。

      修改框架為:

      window.YYC = window.YYC || {};
      ...
      YYC.MyInterface = MyInterface;
      YYC.MyAbstract = MyAbstract;
      YYC.MyClass = MyClass;

      測試頁面中去掉對namespace.js的引用。

      修改類名 

      類名MyInterface、MyAbstract、MyClass太長了,而且個人氣息太濃,因此將類名改為Interface、AClass、Class。

      重構this.base,this.baseToSubClass

      原始版本:

      A.prototype[name] = function (name) {
          return function () {
              //此處不用創建閉包了!因為外面已經創建了閉包,name已經被保存了!
              this.base = function () {
                  //這個寫法也可以!為什么不用apply修正this也行??!
                  //parentClass.prototype[name](); 
      
                  //此處的arguments為base方法傳入的形參
                  //注意!要加上“return”,這樣才能返回parentClass.prototype[name]的返回值
                  return abstractClass.prototype[name].apply(abstractClass.prototype, arguments);
              };
              //指向子類,可以用于模版模式
              this.baseToSubClass = abstractClass.prototype[name];
      
              //執行fn并返回執行的結果
              //此處的arguments為F.prototype[name]方法傳入的形參。
              return prop.Public[name].apply(this, arguments);
          };
      
      }(name);

      原版中,子類使用this.base調用父類同名函數(函數中this指向父類同名函數),子類使用this.baseToSubClass調用父類同名函數(函數中this指向子類同名函數)。

      考慮到一般都是使用this.baseToSubClass,因此將this.base改名為this.baseToParent,this.baseToSubClass改名為this.base,并不再使用this.baseToParent。

      重構版本:

      return function () {
          /*
          //此處不用創建閉包了!因為外面已經創建了閉包,name已經被保存了!
          this.baseToParrent = function () {
              //這個寫法也可以!為什么不用apply修正this也行??!
              //parentClass.prototype[name](); 
      
              //此處的arguments為baseToParrent方法傳入的形參
              //注意!要加上“return”,這樣才能返回parentClass.prototype[name]的返回值
              return parentClass.prototype[name].apply(parentClass.prototype, arguments);
          };
          */
          //指向子類,可以用于模版模式
          this.base = parentClass.prototype[name];
      
          //執行fn并返回執行的結果
          //此處的arguments為F.prototype[name]方法傳入的形參。
          return prop[name].apply(this, arguments);
      };

      重構結構

      分析代碼結構,發現AClass與Class聯系的比較緊密,而Interface則可以單獨為一塊,因此對代碼進行分塊:

      (function(){    //A結構
          (function(){    //A1結構
              function Interface(){
              };
      
              YYC.Interface = Interface;
          }());
      
          (function(){    //A2結構
              function AClass(){
              };
      
              function Class(){
              };
      
              YYC.AClass = AClass;
              YYC.Class = Class;
          }());
      }());

      提取工具函數

      在工具函數的名字中加入前綴“_”,表示為私有函數。

      將Interface、AClass、Class共用的工具函數提出來,放到A中。然后將AClass、Class共用的工具函數提出來放到A2中:

      (function(){    //A結構
          window.YYC = window.YYC || {};
      
          /************************************************** String對象擴展 ***********************************************************
          
          擴展方法:
          contain
          containIgnoreCase
          trim
      
          */
          if (!String.prototype.contain) {
              String.prototype.contain = function (str) {
                  var reg = new RegExp(str);
                  if (this.match(reg)) {  //用this指針指代本體
                      return true;
                  }
                  else {
                      return false;
                  }
              }
          }
      
          /*****************************************************************************************************************************/
      
      
          ////獲得函數的參數數組
          //function argumentNames(fn) {
          //    var names = fn.toString().match(/^[\s\(]*function[^(]*\(([^\)]*)\)/)[1].replace(/\s+/g, '').split(',');
          //    return names.length == 1 && !names[0] ? [] : names;
          //};
      
      
          //獲得函數名
          function _getFunctionName(fn) {
              var name = "";
      
              if (!fn) {
                  return null;
              }
      
              name = fn.toString().match(/^.*function\s*([^\(]*)/);
              return name === null ? name : name[1];
          };
      
          //判斷是否為數組
          function _isArray(val) {
              return Object.prototype.toString.call(val) === "[object Array]";
          };
      
          (function(){    //A1結構
              function Interface(){
              };
          }());
      
          (function(){    //A2結構
              /* 深拷貝
      */
              function _extendDeep(parent, child) {
                  var i = null,
                  len = 0,
                        toStr = Object.prototype.toString,
                        sArr = "[object Array]",
                        sOb = "[object Object]",
                        type = "",
                 _child = null;
      
                  //數組的話,不獲得Array原型上的成員。
                  if (toStr.call(parent) === sArr) {
                      _child = child || [];
      
                      for (i = 0, len = parent.length; i < len; i++) {
                          type = toStr.call(parent[i]);
                          if (type === sArr || type === sOb) {    //如果為數組或object對象
                              _child[i] = type === sArr ? [] : {};
                              _extendDeep(parent[i], _child[i]);
                          } else {
                              _child[i] = parent[i];
                          }
                      }
                  }
                      //對象的話,要獲得原型鏈上的成員。因為考慮以下情景:
                      //類A繼承于類B,現在想要拷貝類A的實例a的成員(包括從類B繼承來的成員),那么就需要獲得原型鏈上的成員。
                  else if (toStr.call(parent) === sOb) {
                      _child = child || {};
      
                      for (i in parent) {
                          //if (parent.hasOwnProperty && parent.hasOwnProperty(i)) {
      
                          //                if (typeof parent[i] === 'object') {    //null === 'object'也為true!
      
                          type = toStr.call(parent[i]);
                          if (type === sArr || type === sOb) {    //如果為數組或object對象
                              _child[i] = type === sArr ? [] : {};
                              _extendDeep(parent[i], _child[i]);
                          } else {
                              _child[i] = parent[i];
                          }
                      }
                      //}
                  }
                  else {
                      _child = parent;
                  }
      
      
                  return _child;
              };
              //獲得在原型prototype中不存在同名的str。
              //如果有同名,則加上前綴"_"
              function _getNoRepeatStrInPrototype(prototype, str) {
                  var new_str = "";
      
                  if (!prototype[str]) {
                      return str;
                  }
                  new_str = "_" + str;
      
                  return _getNoRepeatStrInPrototype(prototype, new_str);
              }
      
              function AClass(){
              };
      
              function Class(){
              };
      
              YYC.AClass = AClass;
              YYC.Class = Class;
          }());
      }());
      View Code

      重構_check函數

      注意到_check函數太大,因此需要根據職責來提取出小函數。

      _check有兩個職責:

      1. 檢查是否實現了父類的抽象方法/屬性。
      2. 檢查是否實現了接口方法/屬性。

      重構前:

      function _check(parentClass, interface, children) {
          var name = "";
      
          if (parentClass) {
              //檢查是否實現了抽象方法/屬性
              for (name in parentClass.prototype) {
                  if (parentClass.prototype.hasOwnProperty(name)) {
                      if (name === "constructor") {
                          continue;
                      }
                      if (name.contain("Abstract_")) {
                          //抽象方法
                          if (typeof parentClass.prototype[name] === "function") {
                              if (children[name.slice(9)] === undefined || typeof children[name.slice(9)] !== "function") {
                                  throw new Error("Abstract method '" + name + "' must be overwrited!");
                              }
                          }
                              //抽象屬性
                          else {
                              if (children[name.slice(9)] === undefined || typeof children[name.slice(9)] === "function") {
                                  throw new Error("Abstract attribute '" + name + "' must be overwrited!");
                              }
                          }
                      }
                  }
              }
          }
          if (!interface) {
              return;
          }
          //檢查是否實現了接口方法/屬性
          for (name in interface.prototype) {
              if (name === "constructor") {
                  continue;
              }
              //接口方法
              if (typeof interface.prototype[name] === "function") {
                  if (children[name.slice(10)] === undefined || typeof children[name.slice(10)] !== "function") {
                      throw new Error("Interface method '" + name + "' must be overwrited!");
                  }
              }
                  //接口屬性
              else {
                  if (children[name.slice(10)] === undefined || typeof children[name.slice(10)] === "function") {
                      throw new Error("Interface attribute '" + name + "' must be overwrited!");
                  }
              }
          }
      };
      View Code

      重構后:

      //檢查子類的公有方法+虛方法+抽象方法是否包含父類的抽象方法/屬性 或 接口方法/屬性。
      //不用hasOwnProperty判斷!否則就檢查不到是否包含了父類的抽象方法/屬性 或 接口方法/屬性。
      function _check(parentClass, interface, children) {
          if (parentClass) {
              _checkAbstract(parentClass, children);
          }
          else if (interface) {
              _checkInterface(interface, children);
          }
      };
      function _checkAbstract(parentClass, children) {
          var name = "";
      
          for (name in parentClass.prototype) {
              if (parentClass.prototype.hasOwnProperty(name)) {
                  if (name === "constructor") {
                      continue;
                  }
                  if (name.contain("Abstract_")) {
                      //抽象方法
                      if (typeof parentClass.prototype[name] === "function") {
                          if (children[name.slice(9)] === undefined || typeof children[name.slice(9)] !== "function") {
                              throw new Error("Abstract method '" + name + "' must be overwrited!");
                          }
                      }
                          //抽象屬性
                      else {
                          if (children[name.slice(9)] === undefined || typeof children[name.slice(9)] === "function") {
                              throw new Error("Abstract attribute '" + name + "' must be overwrited!");
                          }
                      }
                  }
              }
          }
      };
      function _checkInterface(interface, children) {
          var name = "";
      
          for (name in interface.prototype) {
              if (name === "constructor") {
                  continue;
              }
              //接口方法
              if (typeof interface.prototype[name] === "function") {
                  if (children[name.slice(10)] === undefined || typeof children[name.slice(10)] !== "function") {
                      throw new Error("Interface method '" + name + "' must be overwrited!");
                  }
              }
                  //接口屬性
              else {
                  if (children[name.slice(10)] === undefined || typeof children[name.slice(10)] === "function") {
                      throw new Error("Interface attribute '" + name + "' must be overwrited!");
                  }
              }
      
          }
      };
      View Code

      _checkAbstract、_checkInterface中的“if (children[name.slice(9)] === undefined || typeof children[name.slice(9)] !== "function") {”等條件語句很難理解,因此將其封裝成函數:

      function _checkAbstract(parentClass, children) {
          var name = "";
      
          for (name in parentClass.prototype) {
              if (parentClass.prototype.hasOwnProperty(name)) {
                  if (name === "constructor") {
                      continue;
                  }
                  if (name.contain("Abstract_")) {
                      //抽象方法
                      if (typeof parentClass.prototype[name] === "function") {
                          if (_noMethodForAbstract(children, name) && _noMethodForAbstract(parentClass.prototype, name)) {
                              throw new Error("Abstract method '" + name + "' must be overwrited!");
                          }
                      }
                          //抽象屬性
                      else {
                          if (_noAttritubeForAbstract(children, name) && _noAttritubeForAbstract(parentClass.prototype, name)) {
                              throw new Error("Abstract attribute '" + name + "' must be overwrited!");
                          }
                      }
                  }
              }
          }
      };
      function _checkInterface(interface, children) {
          var name = "";
      
          for (name in interface.prototype) {
              if (name === "constructor") {
                  continue;
              }
              //接口方法
              if (typeof interface.prototype[name] === "function") {
                  if (_noMethodForInterface(children, name) && _noMethodForInterface(parentClass.prototype, name)) {
                      throw new Error("Interface method '" + name + "' must be overwrited!");
                  }
              }
                  //接口屬性
              else {
                  if (_noAttritubeForInterface(children, name) && _noAttritubeForInterface(parentClass.prototype, name)) {
                      throw new Error("Interface attribute '" + name + "' must be overwrited!");
                  }
              }
          }
      };
      function _noMethodForAbstract(_class, name) {
          return _class[name.slice(9)] === undefined || typeof _class[name.slice(9)] !== "function";
      };
      function _noAttritubeForAbstract(_class, name) {
          return _class[name.slice(9)] === undefined || typeof _class[name.slice(9)] === "function";
      };
      function _noMethodForInterface(_class, name) {
          return _class[name.slice(10)] === undefined || typeof _class[name.slice(10)] !== "function";
      };
      function _noAttritubeForInterface(_class, name) {
          return _class[name.slice(10)] === undefined || typeof _class[name.slice(10)] === "function";
      };
      View Code

      重構Interface

      現在讓我們看下function Interface(){}中的代碼:

      //創建接口
      //接口可以繼承接口
      function Interface(_parent, _method, _attribute) {
          var i = 0, args = null;
      
          var parent = null,
              method = null,
              attribute = null;
      
          if (typeof _parent === "function") {
              if (_getFunctionName(_parent) !== "I") {
                  throw new Error("Interface must inherit interface!");
              }
              else {
                  parent = _parent;
      
                  //形如“MyInterface(Parent, "A", "B", "GetName");”
                  if (_method && !_isArray(_method)) {
                      method = Array.prototype.slice.call(arguments, 1);
                      attribute = null;
                  }
                      //形如“MyInterface(Parent, ["A", "B", "GetName"], ["a", "c"]);”
                  else {
                      method = _method;
                      attribute = _attribute;
                  }
              }
              //            console.log(parent.toString());
          }
          else {
              parent = null;
              //形如“MyInterface("A", "B", "GetName");”
              if (_method && !_isArray(_method)) {
                  method = arguments
                  attribute = null;
              }
                  //形如“MyInterface(["A", "B", "GetName"], ["a", "c"]);”
              else {
                  method = arguments[0];
                  attribute = arguments[1];
              }
          }
      
          function I() {
          }
      
          // 如果此接口需要從其它接口擴展
          if (parent) {
              I.prototype = new parent();
              I.prototype.constructor = I;
          }
      
          //        console.log("method = " + method);
          //        console.log("attribute = " + attribute);
      
      
          //        //形如“MyInterface(["A", "B", "GetName"], ["a", "c"]);”
          //        if (isArray(method)) {
      
          //方法
          for (i = 0; i < method.length; i++) {
              //加上前綴“Interface_”
              I.prototype["Interface_" + method[i]] = function () {
                  throw new Error("This method must be overwrited!");
              };
          }
          //屬性
          if (attribute) {
              if (!isArray(attribute)) {
                  throw new Error("Attribute must be array!");
              }
              else {
                  for (i = 0; i < attribute.length; i++) {
                      //加上前綴“Interface_”
                      I.prototype["Interface_" + attribute[i]] = 0;
                  }
              }
          }
          //        }
          //        //形如“MyInterface("A", "B", "GetName");”
          //        else {
          //            args = Array.prototype.slice.call(arguments, 1);
          //            //方法
          //            for (i = 0; i < args.length; i++) {
          //                I.prototype[args[i]] = function () {
          //                    throw new Error("This method must be overwrited!");
          //                };
          //            }
          //        }
      
          return I;
      };
      View Code

      該函數包含了太多的職責,應該把每一個職責提取為一個內部函數,然后再在Interface中調用這些內部函數:

      //創建接口
      //接口可以繼承接口
      function Interface(_parent, _method, _attribute) {
          var i = 0, args = null;
          var parent = null,
              method = null,
              attribute = null;
      
          function _getByParent() {
              if (typeof _parent === "function") {
                  if (_getFunctionName(_parent) !== "I") {
                      throw new Error("Interface must inherit interface!");
                  }
                  else {
                      parent = _parent;
                      //形如“Interface(Parent, "A", "B", "GetName");”
                      if (_method && !_isArray(_method)) {
                          method = Array.prototype.slice.call(arguments, 1);
                          attribute = null;
                      }
                          //形如“Interface(Parent, ["A", "B", "GetName"], ["a", "c"]);”
                      else {
                          method = _method;
                          attribute = _attribute;
                      }
                  }
              }
              else {
                  parent = null;
                  //形如“Interface("A", "B", "GetName");”
                  if (_method && !_isArray(_method)) {
                      method = arguments
                      attribute = null;
                  }
                      //形如“Interface(["A", "B", "GetName"], ["a", "c"]);”
                  else {
                      method = arguments[0];
                      attribute = arguments[1];
                  }
              }
          };
          function _inherit() {
              I.prototype = new parent();
              I.prototype.constructor = I;
          };
          function _addMethod() {
              for (i = 0; i < method.length; i++) {
                  //加上前綴“Interface_”
                  I.prototype["Interface_" + method[i]] = function () {
                      throw new Error("This method must be overwrited!");
                  };
              }
          };
          function _addAttribute() {
              if (attribute) {
                  if (!_isArray(attribute)) {
                      throw new Error("Attribute must be array!");
                  }
                  else {
                      for (i = 0; i < attribute.length; i++) {
                          //加上前綴“Interface_”
                          I.prototype["Interface_" + attribute[i]] = 0;
                      }
                  }
              }
          };
      
          function I() {
          }
      
          _getByParent();
          // 如果此接口需要從其它接口擴展
          if (parent) {
              _inherit();
          }
          //方法
          _addMethod();
          //屬性
          _addAttribute();
      
          return I;
      };
      View Code

      重構AClass、Class

      AClass、Class中有一些重復的代碼,將這些重復的代碼提取為函數,放到結構A2中,供AClass、Class調用:

      (function(){    //A2結構
          //檢查抽象成員
          function _addAbstract(abstract, currentClass, temp) {
              var name = "";
      
              for (name in abstract) {
                  if (abstract.hasOwnProperty(name)) {
                      //抽象方法前面加"Abstract_"前綴
                      currentClass.prototype["Abstract_" + name] = abstract[name];
                      temp[name] = abstract[name];    //加入temp
                  }
              }
          };
          //檢查虛方法(不能為虛屬性)
          function _addVirtual(virtual, currentClass, temp) {
              var name = "";
      
              for (name in virtual) {
                  if (virtual.hasOwnProperty(name)) {
                      if (typeof virtual[name] !== "function") {
                          throw new Error("Virtual attribute is not allowed!");
                      }
                      else {
                          currentClass.prototype[name] = virtual[name];
                          temp[name] = virtual[name];    //加入temp
                      }
                  }
              }
          };
          //加入密封方法。
          //沒有實現檢查子類是否重寫了父類的密封方法,只是定義了一個規范。
          function _addSealed(sealed, currentClass, temp) {
              var name = "";
      
              for (name in sealed) {
                  if (sealed.hasOwnProperty(name)) {
                      currentClass.prototype[name] = sealed[name];
                      temp[name] = sealed[name];    //加入temp
                  }
              }
          };
          function _addStatic(_class, prop) {
              var Static = null;
              var k = null;
      
              Static = prop.Static ? prop.Static : null;
              //靜態屬性/方法賦值
              for (k in Static) {
                  _class[k] = Static[k];
              }
          };
          function _inherit(_class, parentClass) {
              _class.prototype = _extendDeep(parentClass.prototype);
              _class.prototype.constructor = _class;
      
              // 如果父類存在,則實例對象的baseClass指向父類的原型。
              // 這就提供了在實例對象中調用父類方法的途徑。
              //baseClass的方法是指向parentClass的,不是指向F(子類)的!
              _class.prototype[_getNoRepeatStrInPrototype(parentClass.prototype, "baseClass")] = parentClass.prototype;
          };
          function _addInit(_class, parentClass, prop) {
              if (prop.Init) {
                  // 如果此類繼承自父類parent并且父類原型中存在同名函數name
                  if (parentClass &&
          typeof prop.Init === "function" &&
          typeof _class.prototype.Init === "function") {
                      //if (parentClass) {
                      _class.prototype.Init = function (name) {
                          return function () {
                              /*
                              //此處不用創建閉包了!因為外面已經創建了閉包,name已經被保存了!
                              this.baseToParrent = function () {
                                  //這個寫法也可以!為什么不用apply修正this也行??!
                                  //parentClass.prototype[name](); 
          
                                  //此處的arguments為baseToParrent方法傳入的形參
                                  //注意!要加上“return”,這樣才能返回parentClass.prototype[name]的返回值
                                  return parentClass.prototype[name].apply(parentClass.prototype, arguments);
                              };
                              */
                              //指向子類,可以用于模版模式
                              this.base = parentClass.prototype[name];
      
                              //執行fn并返回執行的結果
                              //此處的arguments為F.prototype[name]方法傳入的形參。
                              return prop[name].apply(this, arguments);
                          };
      
                      }("Init");
                  }
                  else {
                      _class.prototype.Init = prop.Init;
                  }
              }
          };
          function _addPrivate(_class, private) {
              if (private) {
                  //私有屬性/方法直接覆蓋
                  for (name in private) {
                      if (private.hasOwnProperty(name)) {
                          _class.prototype[name] = private[name];
                      }
                  }
              }
          };
          //檢查抽象類的公有方法+虛方法+抽象方法是否包含父類的抽象方法/屬性 或 接口方法/屬性。
          //不用hasOwnProperty判斷!否則就檢查不到是否包含了父類的抽象方法/屬性 或 接口方法/屬性。
          function _check(parentClass, interface, children) {
              if (parentClass) {
                  _checkAbstract(parentClass, children);
              }
              else if (interface) {
                  _checkInterface(interface, children);
              }
          };
          function _checkAbstract(parentClass, children) {
              var name = "";
      
              for (name in parentClass.prototype) {
                  if (parentClass.prototype.hasOwnProperty(name)) {
                      if (name === "constructor") {
                          continue;
                      }
                      if (name.contain("Abstract_")) {
                          //抽象方法
                          if (typeof parentClass.prototype[name] === "function") {
                              if (_noMethodForAbstract(children, name) && _noMethodForAbstract(parentClass.prototype, name)) {
                                  throw new Error("Abstract method '" + name + "' must be overwrited!");
                              }
                          }
                              //抽象屬性
                          else {
                              if (_noAttritubeForAbstract(children, name) && _noAttritubeForAbstract(parentClass.prototype, name)) {
                                  throw new Error("Abstract attribute '" + name + "' must be overwrited!");
                              }
                          }
                      }
                  }
              }
          };
          function _checkInterface(interface, children) {
              var name = "";
      
              for (name in interface.prototype) {
                  if (name === "constructor") {
                      continue;
                  }
                  //接口方法
                  if (typeof interface.prototype[name] === "function") {
                      if (_noMethodForInterface(children, name) && _noMethodForInterface(parentClass.prototype, name)) {
                          throw new Error("Interface method '" + name + "' must be overwrited!");
                      }
                  }
                      //接口屬性
                  else {
                      if (_noAttritubeForInterface(children, name) && _noAttritubeForInterface(parentClass.prototype, name)) {
                          throw new Error("Interface attribute '" + name + "' must be overwrited!");
                      }
                  }
              }
          };
          function _noMethodForAbstract(_class, name) {
              return _class[name.slice(9)] === undefined || typeof _class[name.slice(9)] !== "function";
          };
          function _noAttritubeForAbstract(_class, name) {
              return _class[name.slice(9)] === undefined || typeof _class[name.slice(9)] === "function";
          };
          function _noMethodForInterface(_class, name) {
              return _class[name.slice(10)] === undefined || typeof _class[name.slice(10)] !== "function";
          };
          function _noAttritubeForInterface(_class, name) {
              return _class[name.slice(10)] === undefined || typeof _class[name.slice(10)] === "function";
          };
      
          function AClass(){
          };
      
          function Class(){
          };
      
          YYC.AClass = AClass;
          YYC.Class = Class;
      }());
      View Code

      將AClass中的每一個職責提取為一個內部函數,然后再在AClass中調用這些內部函數:

      //創建抽象類
      //抽象類能夠繼承接口、抽象類以及實體類,但此處約定抽象類只能繼承接口和抽象類,不能繼承實體類!
      //(這樣方便判斷抽象類是否包含全部的父類(接口/抽象類)成員)
      
      function AClass(_parent, _prop) {
      
          var name = null, temp = {};
          var parentClass = null,
                  interface = null,
              prop = null;
      
          ////原型恢復標志,用于防止第一次創建實例時恢復原型
          //var mark_resume = false;
      
          function _getByParent() {
              //if (arguments.length === 1) {
              if (_prop === undefined) {
                  prop = _parent;
                  parentClass = null;
                  interface = null;
              }
              else if (typeof _parent === "object") {
      
                  if (!_parent.Class && !_parent.Interface) {
                      throw new Error("Please add AbstractClass or Interface!");
                  }
                  if (_getFunctionName(_parent.Class) === "F" || _getFunctionName(_parent.Interface) === "F") {
                      throw new Error("AbstractClass here can't inherit parentClass which is created by Class function!");
                  }
      
                  parentClass = _parent.Class;
                  interface = _parent.Interface;
      
                  prop = _prop;
              }
                  //_parent直接為xx,就表示父類為抽象類
              else if (typeof _parent === "function") {
                  if (_getFunctionName(_parent) === "F") {
                      throw new Error("AbstractClass here can't inherit parentClass which is created by Class function!");
                  }
      
                  parentClass = _parent;
                  interface = null;
      
                  prop = _prop;
              }
              else {
                  throw new Error("arguments is not allowed!");
              }
          };
          function _prepareAndAddPublic() {
              if (prop.Public) {
                  for (name in prop.Public) {
                      if (prop.Public.hasOwnProperty(name)) {
                          if (_prepareCheck("Public") === "continue") {
                              continue;
                          }
                          _addPublic();
                      }
                  }
              }
          };
          function _addPublic() {
              if (parentClass &&
                  typeof prop.Public[name] === "function" &&
                  typeof A.prototype[name] === "function") {
                  A.prototype[name] = function (name) {
                      return function () {
                          /*
                          //此處不用創建閉包了!因為外面已經創建了閉包,name已經被保存了!
                          this.baseToParrent = function () {
                              //這個寫法也可以!為什么不用apply修正this也行??!
                              //parentClass.prototype[name](); 
      
                              //此處的arguments為baseToParrent方法傳入的形參
                              //注意!要加上“return”,這樣才能返回parentClass.prototype[name]的返回值
                              return parentClass.prototype[name].apply(parentClass.prototype, arguments);
                          };
                          */
                          //指向子類,可以用于模版模式
                          this.base = parentClass.prototype[name];
      
                          //執行fn并返回執行的結果
                          //此處的arguments為F.prototype[name]方法傳入的形參。
                          return prop.Public[name].apply(this, arguments);
                      };
      
                  }(name);
              }
              else {
                  A.prototype[name] = prop.Public[name];
              }
          }
          function _prepareAndAddProtected() {
              if (prop.Protected) {
                  for (name in prop.Protected) {
                      if (prop.Protected.hasOwnProperty(name)) {
                          if (_prepareCheck("Protected") === "continue") {
                              continue;
                          }
                          A.prototype[name] = prop.Protected[name];
      
                      }
                  }
              }
          };
          function _prepareCheck(where) {
              //檢查抽象成員,抽象成員放到Public或Protected中
              if (name === "Abstract") {
                  _addAbstract(prop[where][name], A, temp);
                  return "continue";
              }
              //檢查虛方法,虛方法放到Public或Protected中
              if (name === "Virtual") {
                  _addVirtual(prop[where][name], A, temp);
                  return "continue";
              }
              //密封的方法(不允許子類重寫)
              if (name === "Sealed") {
                  _addSealed(prop[where][name], A, temp);
                  return "continue";
              }
      
              temp[name] = prop[where][name];    //用于檢查是否包含父類的抽象方法/屬性 或 接口方法/屬性
              return null;
          };
      
          // 本次調用所創建的類(構造函數)
          function A() {
          }
      
      
          //取出父類、接口
          _getByParent();
      
          // 如果此接口需要從其它接口擴展
          if (parentClass) {
              _inherit(A, parentClass);
          }
      
          //加入構造函數
          //抽象類本身因為不能實例化,所以不調用構造函數。
          //抽象類中的構造函數供子類構造函數中調用。
          _addInit(A, parentClass, prop);
      
          _addPrivate(A, prop.Private);
      
          _prepareAndAddPublic();
      
      
          //保護成員
          _prepareAndAddProtected();
      
          //放到外面的抽象成員,默認為公有抽象成員
          _addAbstract(prop.Abstract, A, temp);
      
          _addStatic(A, prop);
      
          //檢查抽象類的公有方法+虛方法+抽象方法是否包含父類的接口方法/屬性
          _check(null, interface, temp);
      
          return A;
      };
      View Code

      同理Class重構為:

      //創建普通類
      //父類_parent可以為{Class: xx, Interface: xx},或者直接為xx類
      
      function Class(_parent, _prop) {
          //當前是否處于創建類的階段。
          var initializing = false;
          var name = null;
          var parentClass = null, interface = null, prop = null, temp = {};
          //原型恢復標志,用于防止第一次創建實例時恢復原型
          var mark_resume = false;
      
          function _getByParent() {
              if (_prop === undefined) {
                  prop = _parent;
                  parentClass = null;
                  interface = null;
              }
                  //{Class: xx, Interface: xx}
              else if (typeof _parent === "object") {
                  if (!_parent.Class && !_parent.Interface) {
                      throw new Error("Please add Class or Interface!");
                  }
      
                  parentClass = _parent.Class;
                  interface = _parent.Interface;
                  prop = _prop;
              }
                  //直接為xx類
              else if (typeof _parent === "function") {
                  parentClass = _parent;
                  interface = null;
                  prop = _prop;
              }
              else {
                  throw new Error("arguments is not allowed!");
              }
          };
          function _addParentSealed() {
              for (name in parentClass.prototype) {
                  if (parentClass.prototype.hasOwnProperty(name)) {
                      //如果不是抽象方法/保護方法/私有方法/接口成員,則加入到temp中。
                      //用于添加父類的密封方法(因為子類并沒有加入父類的密封方法)。
                      if (!name.match(/^Abstract_/) || !name.match(/^P_/) || !name.match(/^_/) || !name.match(/^Interface_/)) {
                          temp[name] = parentClass.prototype[name];
                      }
                  }
              }
          };
          function _prepareAndAddPublic() {
              if (prop.Public) {
                  for (name in prop.Public) {
                      if (prop.Public.hasOwnProperty(name)) {
                          if (_prepareCheck("Public") === "continue") {
                              continue;
                          }
                          _addPublic();
                      }
                  }
              }
          };
          function _addPublic() {
              // 如果此類繼承自父類parent并且父類原型中存在同名函數name
              if (parentClass &&
      typeof prop.Public[name] === "function" &&
      typeof F.prototype[name] === "function") {
                  F.prototype[name] = function (name) {
                      return function () {
                          //指向子類,可以用于模版模式
                          this.base = parentClass.prototype[name];
                          //執行fn并返回執行的結果
                          //此處的arguments為F.prototype[name]方法傳入的形參。
                          return prop.Public[name].apply(this, arguments);
                      };
                  }(name);
      
              }
              else {
                  F.prototype[name] = prop.Public[name];
              }
          }
          function _prepareAndAddProtected() {
              if (prop.Protected) {
                  for (name in prop.Protected) {
                      if (prop.Protected.hasOwnProperty(name)) {
                          if (_prepareCheck("Protected") === "continue") {
                              continue;
                          }
                          F.prototype[name] = prop.Protected[name];
      
                      }
                  }
              }
          };
          function _prepareCheck(where) {
              //檢查虛方法,虛方法放到Public或Protected中
              if (name === "Virtual") {
                  _addVirtual(prop[where][name], A, temp);
                  return "continue";
              }
              //密封的方法(不允許子類重寫)
              if (name === "Sealed") {
                  _addSealed(prop[where][name], A, temp);
                  return "continue";
              }
      
              temp[name] = prop[where][name];    //用于檢查是否包含父類的抽象方法/屬性 或 接口方法/屬性
              return null;
          };
      
          _getByParent();
      
          // 本次調用所創建的類(構造函數)
          function F() {
              //防止第一次創建實例時恢復原型
              if (mark_resume) {
                  //還原原型
                  _extendDeep(F.backUp_prototype, F.prototype);
              }
              else {
                  mark_resume = true;
              }
      
              // 如果當前處于實例化類的階段,則調用Init原型函數
              if (!initializing) {
                  this.Init && this.Init.apply(this, arguments);
              }
              /*不能刪除私有成員和保護成員!否則類的成員就不能調用到私有和保護的成員了(因為已經刪除了)!
              對象的創建算法參考http://www.rzrgm.cn/TomXu/archive/2012/02/06/2330609.html
      
      
      
      
              //刪除私有成員和保護成員,這樣外界就不能訪問私有和保護成員了!
              for (name in this) {
              if (name.search(/(^_)|(^P_)/) !== -1) {
              delete F.prototype[name];
              //                                                    this[name] = null;
              }
                
              }
              */
          }
      
          // 如果此類需要從其它類擴展
          if (parentClass) {
              initializing = true;
              _inherit(F, parentClass);
              initializing = false;
          }
      
          _addInit(F, parentClass, prop);
      
          if (parentClass) {
              _addParentSealed();
          }
      
          _addPrivate(F, prop.Private);
      
          //保護成員
          _prepareAndAddProtected();
      
          if (prop.Abstract) {
              throw new Error("Only abstractClass can have abstract methods!");
          }
      
          _prepareAndAddPublic();
      
          //檢查公有成員和虛函數是否實現了抽象方法/屬性 或 接口方法/屬性
          _check(parentClass, interface, temp);
      
          _addStatic(F, prop);
      
      
          //備份原型
          F.backUp_prototype = _extendDeep(F.prototype);
      
          return F;
      };
      View Code

      重命名temp

      AClass和Class中的局部屬性temp的職責是存儲該類成員的名稱,從而用于檢查該類成員是否實現了接口或者父類的抽象成員。

      因此,將temp改名為children,這樣能反映職責。

      posted @ 2013-06-08 17:52  楊元超  閱讀(1667)  評論(14)    收藏  舉報
      主站蜘蛛池模板: 人妻系列中文字幕精品| 国内精品无码一区二区三区| 中文字幕人妻精品在线| 商丘市| 国产成人精品a视频| 无码国产一区二区三区四区| 久久国产一区二区日韩av| 喀喇| 国产熟女激情一区二区三区| 一本一道av中文字幕无码| av综合亚洲一区二区| 国产一区二区三区精品综合| 99久久精品久久久久久婷婷| 国产一区| 亚洲欧美成人a∨观看| 国产av中文字幕精品| 亚洲精品国产字幕久久麻豆| 人妻系列无码专区免费| 万山特区| 日韩高清在线亚洲专区不卡| 重口SM一区二区三区视频| 九九热精品视频在线免费| 亚洲 制服 丝袜 无码| 超碰人人模人人爽人人喊手机版| 亚洲丰满熟女一区二区蜜桃| 91蜜臀国产自产在线观看| 么公的好大好硬好深好爽视频| 亚洲欧美国产精品久久久久久久| 日本一区二区三区专线| 在线欧美精品一区二区三区| 国产强奷在线播放免费| 无码专区 人妻系列 在线| 久激情内射婷内射蜜桃| 一级女性全黄久久生活片| av在线播放观看国产| 亚洲乱熟女一区二区三区| 久久超碰97人人做人人爱| 99精品视频在线观看免费蜜桃| av在线播放国产一区| 乌什县| 国产午夜91福利一区二区|