├── README.md ├── dist ├── Class.js └── Utils.js ├── makefile ├── src ├── Class.js └── Utils.js ├── test_browser.html └── test_node.js /README.md: -------------------------------------------------------------------------------- 1 | #BlxClass 2 | 3 | ##GitHub 4 | [https://github.com/bramblex/BlxClass](https://github.com/bramblex/BlxClass) 5 | 6 | ##简介 7 | 一个JavaScript面对对象的库,让你在JavaScript用上靠谱的面对对象特性。 8 | 9 | ##使用 10 | 将本项目中的 ```dist/Class.js``` 复制到你的项目下 11 | 12 | ###1. 在nodejs中使用 13 | 14 | ```JavaScript 15 | var Class = require('path/to/Class.js'); 16 | var ClassA = Class('ClassA', Object); 17 | ``` 18 | 19 | ###2. 在浏览器中使用 20 | 21 | ```Html 22 | 23 | 26 | ``` 27 | 28 | ###3. 用RequireJS加载 29 | BlxClass 同时也符合AMD规范,可以用RequireJS加载 30 | 31 | ```JavaScript 32 | require(['path/to/Class.js'], function(Class){ 33 | var ClassA = Class('ClassA', Object); 34 | }); 35 | ``` 36 | 37 | ##API 38 | 39 | ###1. Class( class\_name, parent\_class) 40 | Class函数接受两个参数返回一个新类,第一个参数是新类的命名,第二个参数是继承自哪个类。如果并没有继承自别的类,那么直接写Object就好了。 41 | 42 | ```JavaScript 43 | var ClassA = Class('ClassA', Object); 44 | var ClassB = Class('ClassB', ClassA); 45 | ``` 46 | 47 | ###2. name 48 | 类的名字 49 | 50 | ```JavaScript 51 | var ClassA = Class('ClassA', Object); 52 | console.log(ClassA.name) // => ClassA 53 | var ClassB = Class('some name', ClassA); 54 | console.log(ClassB.name) // => some name 55 | ``` 56 | 57 | ###3. parent 58 | 类的父类 59 | 60 | ```JavaScript 61 | var ClassA = Class('ClassA', Object); 62 | ClassA.parent === Object; // => true 63 | var ClassB = Class('ClassB', ClassA); 64 | ClassB.parent === ClassA; // => true 65 | ``` 66 | 67 | ###4. method( method\_name, function ) 68 | 定义方法,方法会被子类继承,并且能够重载。 69 | 70 | ```JavaScript 71 | var ClassA = Class('ClassA', Object) 72 | .method('constructor', function(){ 73 | // 构造函数 74 | this.name = 'no name'; 75 | }) 76 | .method('constructor', function(name){ 77 | // 重载构造函数 78 | this.name = name; 79 | }) 80 | .method('run', function(){ 81 | // 普通方法 82 | console.log('run'); 83 | }) 84 | .method('run', function(a,b){ 85 | // 重载上面定义的run方法 86 | console.log('run a, b: ', a, b); 87 | }) 88 | .method('run', '*', function(){ 89 | // 其他任意参数的情况 90 | console.log(arguments); 91 | }); 92 | 93 | var a = ClassA(); 94 | var b = ClassA('Li Lei'); 95 | console.log(a.name); // => no name 96 | console.log(b.name); // => Li Lei 97 | a.run(); // => run 98 | a.run(1,2); // => run a, b: 1 2 99 | a.run(4,5,6); // => [4,5,6] 100 | a.run(7,8,9,0,1,2,3); // => [7,8,9,0,1,2,3] 101 | ``` 102 | 103 | ###5. classmethod( method\_name, function ) 104 | 定义类方法,类方法不会被子类继承,也不能重载。 105 | 106 | ```JavaScript 107 | var ClassA = Class('ClassA', Object) 108 | .classmethod('run', function(){ 109 | // 类方法 110 | console.log('class method run'); 111 | }); 112 | 113 | ClassA.run(); // => class method run 114 | ``` 115 | 116 | ###6. extend( class\_name ) 117 | 继承出新类。 118 | 119 | ```JavaScript 120 | var ClassA = Class('ClassA', Object); 121 | 122 | // 下面两种写法是等价的 123 | var ClassB = Class('ClassB', ClassB); 124 | var ClassB = ClassA.extend('ClassB'); 125 | ``` 126 | 127 | ###7. alias( alias\_name , method\_name ) 128 | 给方法取别名 129 | 130 | ```JavaScript 131 | var ClassA = Class('ClassA', Object) 132 | .method('run', function(){ 133 | // 普通方法 134 | console.log('run'); 135 | }); 136 | 137 | ClassA.alias('aliasRun', 'run'); 138 | 139 | var a = ClassA(); 140 | a.run(); // => run 141 | a.aliasRun(); // => run 142 | a.run === a.aliasRun; // => true 143 | ``` 144 | 145 | ###8. uper( method\_name ) 146 | 调用父类方法 147 | 148 | ```JavaScript 149 | var ClassA = Class('ClassA', Object) 150 | .method('run', function(){ 151 | // 普通方法 152 | console.log('ClassA run'); 153 | }); 154 | 155 | var ClassB = ClassA.extend('ClassB') 156 | .method('run', function(){ 157 | ClassB.uper('run').apply(this, arguments); 158 | console.log('ClassB run'); 159 | }); 160 | 161 | var ClassC = ClassB.extend('ClassC') 162 | .method('run', function(){ 163 | ClassC.uper('run').apply(this, arguments); 164 | console.log('ClassC run'); 165 | }); 166 | 167 | var c = ClassC(); 168 | a.run(); 169 | // => ClassA run 170 | // => ClassB run 171 | // => ClassC run 172 | ``` 173 | -------------------------------------------------------------------------------- /dist/Class.js: -------------------------------------------------------------------------------- 1 | 2 | (function(__root__, __define__){ 3 | var define = function define(dependencies, factory) { 4 | 5 | var factory = factory || dependencies; 6 | var dependencies = (Array.isArray(dependencies) && dependencies) || []; 7 | 8 | if ( typeof __define__ === 'function' && __define__.amd){ 9 | __define__(dependencies, factory); 10 | } else if ( typeof __define__ === 'function' && __define__.cmd){ 11 | __define__(dependencies, function(require, exports, module){ 12 | module.exports = factory.apply(__root__, dependencies.map(function(m){ 13 | return require(m); 14 | })); 15 | }); 16 | } else if (typeof exports === 'object'){ 17 | module.exports = factory.apply(__root__, dependencies.map(function(m){ 18 | return require(m); 19 | })); 20 | } else{ 21 | var name = document.currentScript.src.replace(/(^.*?)([^\/]+)\.(js)(\?.*$|$)/, '$2'); 22 | name = name.replace('.min', ''); 23 | __root__[name] = factory.apply(__root__, dependencies.map(function(m){ 24 | return __root__[m.replace(/^.*\//, '')]; 25 | })); 26 | } 27 | }; 28 | 29 | 30 | define(['./Utils'], function(Utils){ 31 | 32 | var named = function named(name, func){ 33 | var code = func.toString(); 34 | return '(' + code.replace(/(function\s+)(\w*?)\s*(\([\w, ]*?\))/m, '$1'+name+'$3') + ')'; 35 | }; 36 | 37 | var method = function method(name, argc, func){ 38 | if (typeof arguments[1] === 'function'){ 39 | var func = arguments[1]; 40 | var argc = func.length; 41 | } 42 | else if (arguments[1] === '*' && typeof arguments[2] === 'function'){ 43 | var func = arguments[2]; 44 | var argc = '*'; 45 | } 46 | else if (typeof arguments[1] === 'number' && typeof arguments[2] === 'function'){ 47 | var func = arguments[2]; 48 | var argc = arguments[1]; 49 | } 50 | else { 51 | throw new Error('Define method Error!'); 52 | } 53 | 54 | var this_class = this; 55 | 56 | if (name === 'constructor') 57 | name = '__constructor__'; 58 | 59 | if(!this_class.prototype[name] || this_class.prototype[name]['__class__'] !== this_class){ 60 | this_class.prototype[name] = eval(named(this_class.name+'_'+name, function(){ 61 | var methods = this_class['__methods__']; 62 | var method = (methods && ( methods[name][arguments.length] || methods[name]['*'] ) ) || undefined; 63 | if (!method){ 64 | method = this_class.parent.prototype[name]; 65 | if (!method){ 66 | err = Error('method not found!'); 67 | err.stack = err.stack.slice(0, -2); 68 | throw err; 69 | } 70 | } 71 | return method.apply(this, arguments); 72 | })); 73 | this_class.prototype[name]['__class__'] = this_class; 74 | } 75 | 76 | if(!this_class.__methods__) 77 | this_class.__methods__ = {}; 78 | if(!this_class.__methods__[name]) 79 | this_class.__methods__[name] = {}; 80 | this_class.__methods__[name][argc] = func; 81 | 82 | return this; 83 | } 84 | 85 | var classmethod = function classmethod(name, func){ 86 | this[name] = eval(named(this.name+'_class_'+name, function(){ 87 | return func.apply(this, arguments); 88 | })); 89 | this[name]['is_classmethod'] = true; 90 | return this; 91 | } 92 | 93 | var extend = function extend(name){ 94 | return Class(name, this); 95 | }; 96 | 97 | var alias = function alias(name, method){ 98 | this.method(name, '*', this.prototype[method]); 99 | this.prototype[name]['is_alias_to'] = method; 100 | return this; 101 | }; 102 | 103 | var upper = function upper(name){ 104 | var this_class = this; 105 | if (name === 'constructor') 106 | name = '__constructor__'; 107 | return this_class.parent.prototype[name]; 108 | }; 109 | 110 | var inspect = function inspect(){ 111 | var this_class = this; 112 | var methods = Utils.attrs(this.prototype)['all'] 113 | .map(function(method_name){ 114 | var method = this_class.prototype[method_name]; 115 | var method_class = method.__class__; 116 | var is_alias_to = method.is_alias_to; 117 | if (is_alias_to){ 118 | var method_content = method_name + ' -> '+ is_alias_to; 119 | } 120 | else { 121 | var method_content = method_name; 122 | } 123 | if (this_class === method_class){ 124 | return method_content; 125 | } 126 | else{ 127 | return method_class.name + '::' + method_content; 128 | } 129 | }); 130 | var methods_content = 'methods: \n' 131 | + Utils.indent(2, methods.join('\n')); 132 | var classmethods = Utils.attrs(this)['self'] 133 | .filter(function(m){ return this_class[m]['is_classmethod'] || false; }); 134 | var classmethods_content = 'classmethods: \n' 135 | + Utils.indent(2, classmethods.join('\n')); 136 | var content = Utils.indent(2, [classmethods_content, methods_content].join('\n\n')); 137 | return Utils.render( 138 | '[ Class <% class_name %> extend <% parent_class_name %>\n\n<% content %>\n]', 139 | {class_name: this.name, parent_class_name: this.parent.name, content: content}); 140 | }; 141 | 142 | 143 | var Class = function Class(name, parent){ 144 | var parent = parent || Object; 145 | 146 | var child = eval(named(name, function(){ 147 | var this_class = arguments.callee; 148 | var obj; 149 | if(this instanceof this_class){ 150 | if (!!this_class.__sign__){ 151 | delete this_class.__sign__; 152 | return; 153 | } else { 154 | obj = this; 155 | } 156 | } 157 | else{ 158 | this_class.__sign__ = true; 159 | obj = new this_class(); 160 | } 161 | obj.__class__ = this_class; 162 | this_class.prototype['__constructor__'].apply(obj, arguments); 163 | 164 | return obj; 165 | })); 166 | 167 | if (!!parent['parent']) 168 | parent.__sign__ = true; 169 | child.prototype = new parent(); 170 | child.parent = parent; 171 | 172 | // function 173 | child.method = method; 174 | child.classmethod = classmethod; 175 | child.extend = extend; 176 | child.alias = alias; 177 | child.upper = upper; 178 | child.name = name; 179 | child.inspect = inspect; 180 | 181 | child.method('constructor', function(){ 182 | if (child.upper('constructor')) 183 | child.upper('constructor').apply(this, arguments); 184 | }); 185 | 186 | // init 187 | return child; 188 | }; 189 | 190 | return Class; 191 | }); 192 | 193 | 194 | })(this, typeof define !== 'undefined' && define); 195 | -------------------------------------------------------------------------------- /dist/Utils.js: -------------------------------------------------------------------------------- 1 | 2 | (function(__root__, __define__){ 3 | var define = function define(dependencies, factory) { 4 | 5 | var factory = factory || dependencies; 6 | var dependencies = (Array.isArray(dependencies) && dependencies) || []; 7 | 8 | if ( typeof __define__ === 'function' && __define__.amd){ 9 | __define__(dependencies, factory); 10 | } else if ( typeof __define__ === 'function' && __define__.cmd){ 11 | __define__(dependencies, function(require, exports, module){ 12 | module.exports = factory.apply(__root__, dependencies.map(function(m){ 13 | return require(m); 14 | })); 15 | }); 16 | } else if (typeof exports === 'object'){ 17 | module.exports = factory.apply(__root__, dependencies.map(function(m){ 18 | return require(m); 19 | })); 20 | } else{ 21 | var name = document.currentScript.src.replace(/(^.*?)([^\/]+)\.(js)(\?.*$|$)/, '$2'); 22 | name = name.replace('.min', ''); 23 | __root__[name] = factory.apply(__root__, dependencies.map(function(m){ 24 | return __root__[m.replace(/^.*\//, '')]; 25 | })); 26 | } 27 | }; 28 | 29 | define(function(){ 30 | 31 | var Utils = {}; 32 | 33 | Utils.indent = (function(){ 34 | var indentStr = function indentStr(n, s){ 35 | var n = n || 0; 36 | var s = s || ' '; 37 | var str = ''; 38 | for (var i=0; i').map(function(piece){ 111 | var p = piece.split('<%'); 112 | return (p[0] || '') + ((p[1] && hook(values[p[1].replace(/^\s*(\w+)\s*$/,'$1')])) || ''); 113 | }).join(''); 114 | }; 115 | 116 | Utils.inspect = function inspect(obj, depth){ 117 | var indent = Utils.indent; 118 | var inspect = Utils.inspect; 119 | var attrs = Utils.attrs; 120 | 121 | if (typeof depth !== 'number') 122 | var depth = 3; 123 | 124 | if ( obj && typeof obj.inspect === 'function'){ 125 | return obj.inspect(depth); 126 | } 127 | var t = typeof obj; 128 | if (t === 'undefined' ){ 129 | return 'undefined' 130 | } 131 | else if (t === 'boolean' || t === 'number'){ 132 | return obj.toString(); 133 | } 134 | else if (t === 'string'){ 135 | return JSON.stringify(obj); 136 | } 137 | else if (t === 'function'){ 138 | if (obj.name){ 139 | return '[Function: ' + obj.name + ']'; 140 | } 141 | else { 142 | return '[Function]'; 143 | } 144 | } 145 | else if (t === 'object'){ 146 | if (obj === null){ 147 | return 'null' 148 | } 149 | else if (obj instanceof RegExp || obj instanceof Date){ 150 | return obj.toString(); 151 | } 152 | else if (obj instanceof Array){ 153 | if (depth < 0){ 154 | return '[Array]'; 155 | } 156 | else if (obj.length <= 0){ 157 | return '[]'; 158 | } 159 | else { 160 | var content = obj.map(function(item){ 161 | return inspect(item, depth-1); 162 | }); 163 | var content_str = content.join(',\n'); 164 | if (content_str.length < 80){ 165 | content_str = content.join(', '); 166 | } 167 | return '[ ' + indent.skipFirstLine(2, content_str) +' ]'; 168 | } 169 | } 170 | else{ 171 | if (depth < 0){ 172 | return '[Object]'; 173 | } 174 | else { 175 | var keys = attrs(obj).self; 176 | if (keys.length <= 0){ 177 | return '{}'; 178 | } 179 | else { 180 | var content = keys.map(function(key){ 181 | if (/[a-zA-Z_$][a-zA-Z-$0-9]*/.test(key)){ 182 | var key_str = key; 183 | } 184 | else { 185 | var key_str = inspect(key); 186 | } 187 | return key_str + ': ' + inspect(obj[key], depth-1); 188 | }); 189 | var content_str = content.join(',\n'); 190 | if (content_str.length < 80){ 191 | content_str = content.join(', '); 192 | } 193 | return '{ ' + indent.skipFirstLine(2, content_str) +' }'; 194 | } 195 | } 196 | } 197 | } 198 | }; 199 | 200 | Utils.color = (function(){ 201 | var render = Utils.render; 202 | var colors = { 203 | 'bold' : [1, 22], 204 | 'italic' : [3, 23], 205 | 'underline' : [4, 24], 206 | 'inverse' : [7, 27], 207 | 'white' : [37, 39], 208 | 'grey' : [90, 39], 209 | 'black' : [30, 39], 210 | 'blue' : [34, 39], 211 | 'cyan' : [36, 39], 212 | 'green' : [32, 39], 213 | 'magenta' : [35, 39], 214 | 'red' : [31, 39], 215 | 'yellow' : [33, 39] 216 | }; 217 | return function color(c, str){ 218 | return render( 219 | '\u001b[<%left%>m<%str%>\u001b[<%right%>m', 220 | { left: colors[c][0], right: colors[c][1], str: str} 221 | ) 222 | }; 223 | })(); 224 | 225 | Utils.surround = function surround(pair, str){ 226 | var left = pair.substr(0, pair.length/2); 227 | var right = pair.substr(pair.length/2); 228 | return left + str + right; 229 | } 230 | 231 | Utils.merge = function merge(target, obj){ 232 | var attrs = Utils.attrs; 233 | var result = {}; 234 | 235 | var target_keys = attrs(target).self; 236 | var obj_keys = attrs(obj).self; 237 | 238 | target_keys.forEach(function(key){ 239 | result[key] = target[key]; 240 | }); 241 | obj_keys.forEach(function(key){ 242 | result[key] = obj[key]; 243 | }); 244 | return result; 245 | }; 246 | 247 | Utils.kv = function(key, value){ 248 | var obj = {}; 249 | obj[key] = value; 250 | return obj 251 | } 252 | 253 | Utils.importScope = function importScope(name){ 254 | return Utils.render( 255 | 'for (this.__inject_key__ in <%name%>){ eval("var "+this.__inject_key__+"="+"<%name%>"+"."+this.__inject_key__)}; delete this.__inject_key__;' 256 | ,{name: name} 257 | ); 258 | }; 259 | 260 | Utils.uniqueId = (function(){ 261 | var count = 0; 262 | return function uniqueId(){ 263 | return count++; 264 | } 265 | })(); 266 | 267 | Utils.uniqueId.own = function(){ 268 | return (function(){ 269 | var count = 0; 270 | return function uniqueId(){ 271 | return count++; 272 | } 273 | })() 274 | }; 275 | 276 | Utils.equal = function equal(a, b){ 277 | return ( 278 | (typeof a === typeof b) && ( 279 | (a === b) || ( 280 | (typeof a.equal === 'function') 281 | && (!!(a.equal(b))) 282 | ) || ( 283 | (a instanceof Array) && (b instanceof Array) && (Utils.equal.array(a, b)) 284 | ) 285 | ) 286 | ); 287 | }; 288 | 289 | Utils.equal.array = function equalArray(a, b){ 290 | return a.map(function(e, i){ 291 | return [e, b[i]]; 292 | }).reduce(function(last, item){ 293 | return last && Utils.equal(item[0], item[1]); 294 | }, a.length === b.length); 295 | }; 296 | 297 | return Utils; 298 | }); 299 | 300 | 301 | })(this, typeof define !== 'undefined' && define); 302 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | 2 | source_file = $(shell ls src/) 3 | objects = $(foreach o, $(source_file), $(subst .js, ,$(o))) 4 | target_files = $(foreach o, $(objects), dist/$(o).js) 5 | umdt = 'umdt' 6 | 7 | .PHONY: all 8 | all: dist $(target_files) 9 | 10 | dist: 11 | @mkdir -p dist 12 | 13 | $(target_files):dist/%.js:src/%.js 14 | umdt $< $@ 15 | 16 | .PHONY: clean 17 | clean: 18 | rm -r dist 19 | -------------------------------------------------------------------------------- /src/Class.js: -------------------------------------------------------------------------------- 1 | 2 | define(['./Utils'], function(Utils){ 3 | 4 | var named = function named(name, func){ 5 | var code = func.toString(); 6 | return '(' + code.replace(/(function\s+)(\w*?)\s*(\([\w, ]*?\))/m, '$1'+name+'$3') + ')'; 7 | }; 8 | 9 | var method = function method(name, argc, func){ 10 | if (typeof arguments[1] === 'function'){ 11 | var func = arguments[1]; 12 | var argc = func.length; 13 | } 14 | else if (arguments[1] === '*' && typeof arguments[2] === 'function'){ 15 | var func = arguments[2]; 16 | var argc = '*'; 17 | } 18 | else if (typeof arguments[1] === 'number' && typeof arguments[2] === 'function'){ 19 | var func = arguments[2]; 20 | var argc = arguments[1]; 21 | } 22 | else { 23 | throw new Error('Define method Error!'); 24 | } 25 | 26 | var this_class = this; 27 | 28 | if (name === 'constructor') 29 | name = '__constructor__'; 30 | 31 | if(!this_class.prototype[name] || this_class.prototype[name]['__class__'] !== this_class){ 32 | this_class.prototype[name] = eval(named(this_class.name+'_'+name, function(){ 33 | var methods = this_class['__methods__']; 34 | var method = (methods && ( methods[name][arguments.length] || methods[name]['*'] ) ) || undefined; 35 | if (!method){ 36 | method = this_class.parent.prototype[name]; 37 | if (!method){ 38 | err = Error('method not found!'); 39 | err.stack = err.stack.slice(0, -2); 40 | throw err; 41 | } 42 | } 43 | return method.apply(this, arguments); 44 | })); 45 | this_class.prototype[name]['__class__'] = this_class; 46 | } 47 | 48 | if(!this_class.__methods__) 49 | this_class.__methods__ = {}; 50 | if(!this_class.__methods__[name]) 51 | this_class.__methods__[name] = {}; 52 | this_class.__methods__[name][argc] = func; 53 | 54 | return this; 55 | } 56 | 57 | var classmethod = function classmethod(name, func){ 58 | this[name] = eval(named(this.name+'_class_'+name, function(){ 59 | return func.apply(this, arguments); 60 | })); 61 | this[name]['is_classmethod'] = true; 62 | return this; 63 | } 64 | 65 | var extend = function extend(name){ 66 | return Class(name, this); 67 | }; 68 | 69 | var alias = function alias(name, method){ 70 | this.method(name, '*', this.prototype[method]); 71 | this.prototype[name]['is_alias_to'] = method; 72 | return this; 73 | }; 74 | 75 | var upper = function upper(name){ 76 | var this_class = this; 77 | if (name === 'constructor') 78 | name = '__constructor__'; 79 | return this_class.parent.prototype[name]; 80 | }; 81 | 82 | var inspect = function inspect(){ 83 | var this_class = this; 84 | var methods = Utils.attrs(this.prototype)['all'] 85 | .map(function(method_name){ 86 | var method = this_class.prototype[method_name]; 87 | var method_class = method.__class__; 88 | var is_alias_to = method.is_alias_to; 89 | if (is_alias_to){ 90 | var method_content = method_name + ' -> '+ is_alias_to; 91 | } 92 | else { 93 | var method_content = method_name; 94 | } 95 | if (this_class === method_class){ 96 | return method_content; 97 | } 98 | else{ 99 | return method_class.name + '::' + method_content; 100 | } 101 | }); 102 | var methods_content = 'methods: \n' 103 | + Utils.indent(2, methods.join('\n')); 104 | var classmethods = Utils.attrs(this)['self'] 105 | .filter(function(m){ return this_class[m]['is_classmethod'] || false; }); 106 | var classmethods_content = 'classmethods: \n' 107 | + Utils.indent(2, classmethods.join('\n')); 108 | var content = Utils.indent(2, [classmethods_content, methods_content].join('\n\n')); 109 | return Utils.render( 110 | '[ Class <% class_name %> extend <% parent_class_name %>\n\n<% content %>\n]', 111 | {class_name: this.name, parent_class_name: this.parent.name, content: content}); 112 | }; 113 | 114 | 115 | var Class = function Class(name, parent){ 116 | var parent = parent || Object; 117 | 118 | var child = eval(named(name, function(){ 119 | var this_class = arguments.callee; 120 | var obj; 121 | if(this instanceof this_class){ 122 | if (!!this_class.__sign__){ 123 | delete this_class.__sign__; 124 | return; 125 | } else { 126 | obj = this; 127 | } 128 | } 129 | else{ 130 | this_class.__sign__ = true; 131 | obj = new this_class(); 132 | } 133 | obj.__class__ = this_class; 134 | this_class.prototype['__constructor__'].apply(obj, arguments); 135 | 136 | return obj; 137 | })); 138 | 139 | if (!!parent['parent']) 140 | parent.__sign__ = true; 141 | child.prototype = new parent(); 142 | child.parent = parent; 143 | 144 | // function 145 | child.method = method; 146 | child.classmethod = classmethod; 147 | child.extend = extend; 148 | child.alias = alias; 149 | child.upper = upper; 150 | child.name = name; 151 | child.inspect = inspect; 152 | 153 | child.method('constructor', function(){ 154 | if (child.upper('constructor')) 155 | child.upper('constructor').apply(this, arguments); 156 | }); 157 | 158 | // init 159 | return child; 160 | }; 161 | 162 | return Class; 163 | }); 164 | -------------------------------------------------------------------------------- /src/Utils.js: -------------------------------------------------------------------------------- 1 | define(function(){ 2 | 3 | var Utils = {}; 4 | 5 | Utils.indent = (function(){ 6 | var indentStr = function indentStr(n, s){ 7 | var n = n || 0; 8 | var s = s || ' '; 9 | var str = ''; 10 | for (var i=0; i').map(function(piece){ 83 | var p = piece.split('<%'); 84 | return (p[0] || '') + ((p[1] && hook(values[p[1].replace(/^\s*(\w+)\s*$/,'$1')])) || ''); 85 | }).join(''); 86 | }; 87 | 88 | Utils.inspect = function inspect(obj, depth){ 89 | var indent = Utils.indent; 90 | var inspect = Utils.inspect; 91 | var attrs = Utils.attrs; 92 | 93 | if (typeof depth !== 'number') 94 | var depth = 3; 95 | 96 | if ( obj && typeof obj.inspect === 'function'){ 97 | return obj.inspect(depth); 98 | } 99 | var t = typeof obj; 100 | if (t === 'undefined' ){ 101 | return 'undefined' 102 | } 103 | else if (t === 'boolean' || t === 'number'){ 104 | return obj.toString(); 105 | } 106 | else if (t === 'string'){ 107 | return JSON.stringify(obj); 108 | } 109 | else if (t === 'function'){ 110 | if (obj.name){ 111 | return '[Function: ' + obj.name + ']'; 112 | } 113 | else { 114 | return '[Function]'; 115 | } 116 | } 117 | else if (t === 'object'){ 118 | if (obj === null){ 119 | return 'null' 120 | } 121 | else if (obj instanceof RegExp || obj instanceof Date){ 122 | return obj.toString(); 123 | } 124 | else if (obj instanceof Array){ 125 | if (depth < 0){ 126 | return '[Array]'; 127 | } 128 | else if (obj.length <= 0){ 129 | return '[]'; 130 | } 131 | else { 132 | var content = obj.map(function(item){ 133 | return inspect(item, depth-1); 134 | }); 135 | var content_str = content.join(',\n'); 136 | if (content_str.length < 80){ 137 | content_str = content.join(', '); 138 | } 139 | return '[ ' + indent.skipFirstLine(2, content_str) +' ]'; 140 | } 141 | } 142 | else{ 143 | if (depth < 0){ 144 | return '[Object]'; 145 | } 146 | else { 147 | var keys = attrs(obj).self; 148 | if (keys.length <= 0){ 149 | return '{}'; 150 | } 151 | else { 152 | var content = keys.map(function(key){ 153 | if (/[a-zA-Z_$][a-zA-Z-$0-9]*/.test(key)){ 154 | var key_str = key; 155 | } 156 | else { 157 | var key_str = inspect(key); 158 | } 159 | return key_str + ': ' + inspect(obj[key], depth-1); 160 | }); 161 | var content_str = content.join(',\n'); 162 | if (content_str.length < 80){ 163 | content_str = content.join(', '); 164 | } 165 | return '{ ' + indent.skipFirstLine(2, content_str) +' }'; 166 | } 167 | } 168 | } 169 | } 170 | }; 171 | 172 | Utils.color = (function(){ 173 | var render = Utils.render; 174 | var colors = { 175 | 'bold' : [1, 22], 176 | 'italic' : [3, 23], 177 | 'underline' : [4, 24], 178 | 'inverse' : [7, 27], 179 | 'white' : [37, 39], 180 | 'grey' : [90, 39], 181 | 'black' : [30, 39], 182 | 'blue' : [34, 39], 183 | 'cyan' : [36, 39], 184 | 'green' : [32, 39], 185 | 'magenta' : [35, 39], 186 | 'red' : [31, 39], 187 | 'yellow' : [33, 39] 188 | }; 189 | return function color(c, str){ 190 | return render( 191 | '\u001b[<%left%>m<%str%>\u001b[<%right%>m', 192 | { left: colors[c][0], right: colors[c][1], str: str} 193 | ) 194 | }; 195 | })(); 196 | 197 | Utils.surround = function surround(pair, str){ 198 | var left = pair.substr(0, pair.length/2); 199 | var right = pair.substr(pair.length/2); 200 | return left + str + right; 201 | } 202 | 203 | Utils.merge = function merge(target, obj){ 204 | var attrs = Utils.attrs; 205 | var result = {}; 206 | 207 | var target_keys = attrs(target).self; 208 | var obj_keys = attrs(obj).self; 209 | 210 | target_keys.forEach(function(key){ 211 | result[key] = target[key]; 212 | }); 213 | obj_keys.forEach(function(key){ 214 | result[key] = obj[key]; 215 | }); 216 | return result; 217 | }; 218 | 219 | Utils.kv = function(key, value){ 220 | var obj = {}; 221 | obj[key] = value; 222 | return obj 223 | } 224 | 225 | Utils.importScope = function importScope(name){ 226 | return Utils.render( 227 | 'for (this.__inject_key__ in <%name%>){ eval("var "+this.__inject_key__+"="+"<%name%>"+"."+this.__inject_key__)}; delete this.__inject_key__;' 228 | ,{name: name} 229 | ); 230 | }; 231 | 232 | Utils.uniqueId = (function(){ 233 | var count = 0; 234 | return function uniqueId(){ 235 | return count++; 236 | } 237 | })(); 238 | 239 | Utils.uniqueId.own = function(){ 240 | return (function(){ 241 | var count = 0; 242 | return function uniqueId(){ 243 | return count++; 244 | } 245 | })() 246 | }; 247 | 248 | Utils.equal = function equal(a, b){ 249 | return ( 250 | (typeof a === typeof b) && ( 251 | (a === b) || ( 252 | (typeof a.equal === 'function') 253 | && (!!(a.equal(b))) 254 | ) || ( 255 | (a instanceof Array) && (b instanceof Array) && (Utils.equal.array(a, b)) 256 | ) 257 | ) 258 | ); 259 | }; 260 | 261 | Utils.equal.array = function equalArray(a, b){ 262 | return a.map(function(e, i){ 263 | return [e, b[i]]; 264 | }).reduce(function(last, item){ 265 | return last && Utils.equal(item[0], item[1]); 266 | }, a.length === b.length); 267 | }; 268 | 269 | return Utils; 270 | }); 271 | -------------------------------------------------------------------------------- /test_browser.html: -------------------------------------------------------------------------------- 1 |

Test BlxScript in Browser

2 | 3 | 4 | 28 | -------------------------------------------------------------------------------- /test_node.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var Class = require('./dist/Class'); 4 | 5 | var A = Class('A', Object) 6 | .method('constructor', function(){ 7 | this.name = 'a'; 8 | }); 9 | 10 | var B = Class('B', A); 11 | B.method('run', function(){ 12 | console.log('run'); 13 | }); 14 | 15 | var C = B.extend('C') 16 | .method('run', function(a){ 17 | console.log('run a: ', a); 18 | }) 19 | .method('run', function(a,b){ 20 | console.log('run a, b: ', a, b); 21 | }); 22 | 23 | var c = C(); 24 | c.run(); 25 | c.run(1); 26 | c.run(1,2); 27 | --------------------------------------------------------------------------------