js继承类库,根据henry_feng改造的轮子

原文地址:http://blog.csdn.net/henry_feng

集成类实现以下功能:

  • 类注册register
  • 类创建及初始化createClass
  • 子类中显示初始化父类:base(..)
  • 私有方法,不支持继承private
  • 多继承
  • 继承多态virtual
  • 子类中调用基类方法base(["basename"]).
  • 函数覆盖override
  • 抽象类abstract
  • 静态构造createInstance
  • instanceOf测试
  • 方法支持in测试

先贴例子:

基类:

 1 define(["oo", "exports"], function (oo, exports) {
 2 
 3     var s = function () {
 4         var privateval = "base";
 5         var a = Array.prototype.slice.call(arguments);
 6 
 7         this.getInitParamater = function () {//私用方法,不会被继承
 8             return a;
 9         }
10 
11         this.baseGet = function () {//私用方法,不会被继承
12             return privateval;
13         }
14     }
15     s.prototype.getName = function () {//可以被继承的方法
16         return this.baseGet();
17     }
18 
19     s.prototype.virtualGet = function () {
20         return this.getName();//多态
21     }
22 
23     s.prototype.trueVirtual = function () {
24         throw new TypeError("trueVirtual");//模拟abstract
25     }
26 
27     oo.register("xxxxxxx.OOTest.OoBase", s);//注册类
28 
29 });

子类:

 1 define(["oo", "require", "exports"], function (oo, require, exports) {
 2 
 3     var s = function (a, b) {
 4         var _super = this.base("xxxxxx.OOTest.OoBase", a, b);//开头初始化基类并得到操作对象
 5 
 6         var privateval = "sub";//私有变量
 7 
 8         this.subGet= function () {
 9             return privateval;
10         }
11 
12         this.baseGetName = function () {
13             return _super.getName();//内部调用基类方法
14         }
15     }
16 
17     s.prototype.getName = function () {//覆盖
18         return this.subGet();
19     }
20 
21     s.parent = "xxxxxxxx.OOTest.OoBase";
22 
23     oo.register("xxxxxxxx.OOTest.OoSub", s);
24 
25     return s;
26 });

库:

  1 define(function (require, exports, module) {
  2     var oofactory = {
  3         _: {},
  4         DEBUG: true
  5     };
  6 
  7     var pkg = null;
  8 
  9     var isRoot = function (root) {
 10         return root && (isWindow(root) || isObject(root));
 11     }
 12 
 13     var isFunction = function (fun) {
 14         return typeof (fun) === "function";
 15     }
 16 
 17     var isObject = function (obj) {
 18         var type = typeof obj;
 19         return type === 'function' || type === 'object' && !!obj;
 20     }
 21 
 22     var isWindow = function (obj) {
 23         /* jshint eqeqeq: false */
 24         return obj != null && obj == obj.window;
 25     }
 26 
 27     var isArray = function (obj) {
 28         return toString.call(obj) === '[object Array]'
 29     }
 30 
 31     var contains = function (arr, str) {
 32         if (!arr || !isArray(arr)) return -1;
 33         for (var i = 0; i < arr.length; i++) {
 34             if (arr[i] === str) {
 35                 return i;
 36             }
 37         }
 38         return -1;
 39     }
 40 
 41     //function inhertPrototype(sub, _super) {
 42     //    var prototype = object(_super.prototype);
 43     //    prototype.constructor = sub;
 44     //    sub.prototype = prototype;
 45     //}
 46 
 47     //function isPrototypeProperty(obj, name) {
 48     //    return !(name in obj) && !obj.hasOwnProperty(name);
 49     //}
 50 
 51     //function isProperty(obj, name) {
 52     //    return name in obj;
 53     //}
 54 
 55     //var inject = function (obj, _super) {
 56     //    //只往当前this上绑定,通过context实现递归复制
 57     //    for (var x in _super) {
 58     //        obj[x] = obj[x] || (
 59     //            isFunction(_super[x]) ?
 60     //            cloneFunction(_super[x]) :
 61     //            _super[x]);
 62     //    }
 63     //    return _super;
 64     //}
 65     var cloneFunction = function (funres) {
 66         var temp = function temporary() { return funres.apply(this, arguments); };
 67         for (key in funres) {
 68             temp[key] = funres[key];
 69         }
 70         return temp;
 71     }
 72 
 73     var injectprototype = function (obj, clazz) {
 74         var prototype = clazz.prototype;
 75         for (var p in prototype) {
 76             if (p == "constructor" || p == "__proto__") continue;
 77             obj[p] = isFunction(prototype[p]) ? cloneFunction(prototype[p]) : prototype[p];
 78         }
 79     }
 80 
 81     var JOObject = function (className) {
 82         this._ = [];
 83         this.className = className || "JOObject";
 84     }
 85 
 86     JOObject.className = "JOObject";
 87 
 88     JOObject.prototype.getClassName = function () {
 89         return this.className;
 90     }
 91 
 92     JOObject.prototype.base = function (baseName) {
 93         var index = -1;
 94         if (!baseName) {
 95             if (this._.length) return this._[1];
 96         }
 97         else if ((index = contains(this._, baseName)) > -1) {
 98             return this._[index + 1];
 99         }
100         //继承
101         var parent = oofactory.classForName(baseName);
102         //这个是复制构造函数中的this定义的方法,不复制相当于选择继承的方式,全复制则打开即可
103         //parent.apply(this, Array.prototype.slice(arguments, 1));
104         //复制prototype定义的方法
105         injectprototype(this, parent);
106         //父类
107         var _super = oofactory.createClass.apply(null, Array.prototype.slice.call(arguments));
108         //搭建关系
109         this._.push(baseName);
110         this._.push(_super);
111         return _super;
112     }
113 
114     JOObject.prototype.instanceOf = function (baseName) {
115         if (baseName == this.getClassName() || baseName == JOObject.className) {
116             return true;
117         }
118         index = contains(this._, baseName);
119         if (index > -1) return true;
120         for (var i = 1; i < this._.length; i += 2) {
121             var basei = this._[i];
122             if (basei.instanceOf(baseName)) {
123                 return true;
124             }
125         }
126         return false;
127     }
128 
129     var Package = function () {
130 
131         this.createClassPkg = function (className) {
132             this.createPackage(this.getParent(className));
133         };
134 
135         this.classForName = function (className) {
136             var ns = className.split(".");
137             var np = oofactory._;
138             for (var j = 0; j < ns.length; j++) {
139                 var name = ns[j];
140                 if (np[name] === undefined) {
141                     return np[name];
142                 }
143                 np = np[name];
144             }
145             return np;
146         };
147 
148         this.createPackage = function (pkgName) {
149             var ns = pkgName.split(".");
150             var np = oofactory._;
151             for (var j = 0; j < ns.length; j++) {
152                 var name = ns[j];
153                 if (np[name] === undefined) {
154                     console.log("create package: " + name);
155                 }
156                 np[name] = np[name] || {};
157                 np = np[name];
158             }
159             return np;
160         };
161 
162         this.getPackage = function (className) {
163             var pkgName = this.getParent(className);
164             return this.createPackage(pkgName);
165         };
166 
167         this.getParent = function (className) {
168             var idx = className.lastIndexOf(".");
169             if (idx > 0) {
170                 return className.substr(0, idx);
171             } else {
172                 return "";
173             }
174         };
175 
176         this.getSimpleName = function (className) {
177             var idx = className.lastIndexOf(".");
178             if (idx > 0) {
179                 return className.substr(idx + 1);
180             } else {
181                 return className;
182             }
183         };
184     }
185 
186     oofactory.register = function (className, clazz, parents) {
187         if (clazz['createInstance'] == null) {//静态方法
188             clazz['createInstance'] = function () {
189                 return oofactory.createClass.apply(null, [className].concat(Array.prototype.slice.call(arguments)));
190             };
191         }
192 
193         if (clazz['className'] == null) {//静态方法
194             clazz['className'] = className;
195         }
196 
197         //默认注册到window上
198         if (isRoot(oofactory._)) {
199             pkg = pkg || new Package(oofactory._);
200             var pkgName = pkg.getPackage(className);
201             pkgName[pkg.getSimpleName(className)] = clazz;
202         }
203     };
204 
205     oofactory.createClass = function () {
206         var args = Array.prototype.slice.call(arguments);
207         var className = args[0];
208         var clazz = oofactory.classForName(className);
209         var obj = new JOObject(className);
210         clazz.apply(obj, args.slice(1));
211         injectprototype(obj,clazz);
212         return obj;
213     };
214 
215     oofactory.classForName = function (className) {
216         if (!className || JOObject.className === className) return JOObject;
217         pkg = pkg || new Package(oofactory._);
218         return pkg.classForName(className);
219     };
220 
221     return oofactory;
222 });
轮子

自动化测试例子,可以参考学习:

  1 define([
  2     'underscore',
  3     'oo',
  4     'require',
  5     'boot',
  6     './oo_package/oo_base',
  7     './oo_package/oo_sub'
  8 ],
  9 function (_, oo, require, sub) {
 10     'use strict';
 11 
 12     describe("[oo test]", function () {
 13 
 14         beforeEach(function () {
 15             spyOn(oo, 'register');
 16         });
 17         
 18         it("register类注册测试", function () {
 19             expect(_.isObject(oo._.xxxxx.OOTest.OoBase)).toBe(true);
 20             expect(_.isObject(oo._.xxxxx.OOTest.OoSub)).toBe(true);
 21         });
 22 
 23         it("new-createClass创建类", function () {
 24             var b = oo.createClass("xxxxx.OOTest.OoBase", 1, 2);
 25             expect(_.isObject(b)).toBe(true);
 26             expect(b.getInitParamater()).toEqual([1, 2]);
 27         });
 28 
 29         it("private私有方法", function () {
 30             var b = oo.createClass("xxxxx.OOTest.OoBase");
 31             expect(b.baseGet()).toEqual("base");
 32             var c = oo.createClass("xxxxx.OOTest.OoSub");
 33             expect("baseGet" in c).toBe(false);
 34             expect("getInitParamater" in c).toBe(false);
 35         });
 36 
 37         it("virtual继承多态", function () {
 38             var b = oo.createClass("xxxxx.OOTest.OoBase");
 39             expect(b.virtualGet()).toEqual("base");//多态
 40             var c = oo.createClass("xxxxx.OOTest.OoSub");
 41             expect(c.virtualGet()).toEqual("sub");//继承+多态
 42         });
 43 
 44         it("base父类调用", function () {
 45             var b = oo.createClass("xxxxx.OOTest.OoSub");
 46             expect(b.baseGetName()).toEqual("base");//调用父类方法
 47             expect(b.base().virtualGet()).toEqual("base");
 48         });
 49 
 50         it("over覆盖父类调用", function () {
 51             var b = oo.createClass("xxxxx.OOTest.OoSub");
 52             expect(b.getName()).toEqual("sub");//调用父类方法
 53             expect(b.base().getName()).toEqual("base");
 54         });
 55         
 56         it("abstract抽象方法", function () {
 57             var b = oo.createClass("xxxxx.OOTest.OoSub");
 58             expect(b.trueVirtual).toThrowError(TypeError, "trueVirtual");//抽象方法
 59         });
 60         
 61         it(":base(1,2)初始化父类构造函数测试", function () {
 62             var b = oo.createClass("xxxxx.OOTest.OoSub", "a", "b");
 63             expect(b.base().getInitParamater()).toEqual(["a", "b"]);
 64         });
 65 
 66         it("base.调用基类方法", function () {
 67             var b = oo.createClass("xxxxx.OOTest.OoSub");
 68             expect(b.base("xxxxx.OOTest.OoBase").getName()).toEqual("base");
 69             expect(b.base().getName()).toEqual("base");
 70         });
 71 
 72         it("createInstance静态构造", function () {
 73             var a = oo.classForName("xxxxx.OOTest.OoBase").createInstance(1, 2);
 74             expect(_.isObject(a)).toBe(true);
 75             expect(a.getInitParamater()).toEqual([1, 2]);
 76             //expect(a.privateGet()).toEqual("base");//非虚函数
 77             expect(a.virtualGet()).toEqual("base");//多态
 78             var b = oo.classForName("xxxxx.OOTest.OoSub").createInstance();
 79             expect(b.baseGetName()).toEqual("base");//调用父类方法
 80            // expect(b.privateGet()).toEqual("base");
 81             expect(b.virtualGet()).toEqual("sub");//继承+多态
 82             expect(b.trueVirtual).toThrowError(TypeError, "trueVirtual");//抽象方法
 83         });
 84 
 85         it("static静态方法", function () {
 86             expect(oo.classForName("xxxxx.OOTest.OoSub").parent).toEqual("xxxxx.OOTest.OoBase");
 87         });
 88 
 89         it("instanceof实例", function () {
 90             expect(oo.createClass("xxxxx.OOTest.OoSub").instanceOf("xxxxx.OOTest.OoSub")).toBe(true);
 91             expect(oo.createClass("xxxxx.OOTest.OoSub").instanceOf("xxxxx.OOTest.OoBase")).toBe(true);
 92             expect(oo.createClass("xxxxx.OOTest.OoSub").instanceOf("JOObject")).toBe(true);
 93         });
 94 
 95         it("in方法", function () {
 96             expect("getName" in oo.createClass("xxxxx.OOTest.OoSub")).toBe(true);
 97             expect("getName" in oo.createClass("xxxxx.OOTest.OoSub").base()).toBe(true);
 98         });
 99 
100         it("getType类名", function () {
101             expect(oo.createClass("xxxxx.OOTest.OoSub").className).toEqual("xxxxx.OOTest.OoSub");
102         });
103 
104         it("getType继承类名测试", function () {
105             var b = oo.createClass("xxxxx.OOTest.OoSub");
106             expect(b.getClassName()).toEqual("xxxxx.OOTest.OoSub");
107             expect(b.base().getClassName()).toEqual("xxxxx.OOTest.OoBase");
108         });
109 
110         afterEach(function () {
111         });
112         return {};
113     });
114     window.onload();
115 });
自动化测试

 

posted on 2016-01-12 16:19  learning...  阅读(295)  评论(0)    收藏  举报

导航