UNPKG

kityminder

Version:
401 lines (364 loc) 11.9 kB
/** * @fileOverview * * 提供 Kity 的 OOP 支持 */ define(function(require, exports) { /** * @class kity.Class * @catalog core * @description 所有 kity 类的基类 * @abstract */ function Class() {} exports.Class = Class; Class.__KityClassName = 'Class'; /** * @method base() * @for kity.Class * @protected * @grammar base(name, args...) => {any} * @description 调用父类指定名称的函数 * @param {string} name 函数的名称 * @param {parameter} args... 传递给父类函数的参数 * * @example * * ```js * var Person = kity.createClass('Person', { * toString: function() { * return 'I am a person'; * } * }); * * var Male = kity.createClass('Male', { * base: Person, * * toString: function() { * return 'I am a man'; * }, * * speak: function() { * return this.base('toString') + ',' + this.toString(); * } * }) * ``` */ Class.prototype.base = function(name) { var caller = arguments.callee.caller; var method = caller.__KityMethodClass.__KityBaseClass.prototype[name]; return method.apply(this, Array.prototype.slice.call(arguments, 1)); }; /** * @method callBase() * @for kity.Class * @protected * @grammar callBase(args...) => {any} * @description 调用父类同名函数 * @param {parameter} args... 传递到父类同名函数的参数 * * @example * * ```js * var Animal = kity.createClass('Animal', { * constructor: function(name) { * this.name = name; * }, * toString: function() { * return 'I am an animal name ' + this.name; * } * }); * * var Dog = kity.createClass('Dog', { * constructor: function(name) { * this.callBase(name); * }, * toString: function() { * return this.callBase() + ', a dog'; * } * }); * * var dog = new Dog('Dummy'); * console.log(dog.toString()); // "I am an animal name Dummy, a dog"; * ``` */ Class.prototype.callBase = function() { var caller = arguments.callee.caller; var method = caller.__KityMethodClass.__KityBaseClass.prototype[caller.__KityMethodName]; return method.apply(this, arguments); }; Class.prototype.mixin = function(name) { var caller = arguments.callee.caller; var mixins = caller.__KityMethodClass.__KityMixins; if (!mixins) { return this; } var method = mixins[name]; return method.apply(this, Array.prototype.slice.call(arguments, 1)); }; Class.prototype.callMixin = function() { var caller = arguments.callee.caller; var methodName = caller.__KityMethodName; var mixins = caller.__KityMethodClass.__KityMixins; if (!mixins) { return this; } var method = mixins[methodName]; if (methodName == 'constructor') { for (var i = 0, l = method.length; i < l; i++) { method[i].call(this); } return this; } else { return method.apply(this, arguments); } }; /** * @method pipe() * @for kity.Class * @grammar pipe() => {this} * @description 以当前对象为上线文以及管道函数的第一个参数,执行一个管道函数 * @param {Function} fn 进行管道操作的函数 * * @example * * ```js * var rect = new kity.Rect().pipe(function() { * this.setWidth(500); * this.setHeight(300); * }); * ``` */ Class.prototype.pipe = function(fn) { if (typeof(fn) == 'function') { fn.call(this, this); } return this; }; /** * @method getType() * @for kity.Class * @grammar getType() => {string} * @description 获得对象的类型 * * @example * * ```js * var rect = new kity.Rect(); * var circle = new kity.Circle(); * * console.log(rect.getType()); // "Rect" * console.log(rect.getType()); // "Circle" * ``` */ Class.prototype.getType = function() { return this.__KityClassName; }; /** * @method getClass() * @for kity.Class * @grammar getClass() => {Class} * @description 获得对象的类 * * @example * * ```js * var rect = new kity.Rect(); * * console.log(rect.getClass() === kity.Rect); // true * console.log(rect instanceof kity.Rect); // true * ``` */ Class.prototype.getClass = function() { return this.constructor; }; // 检查基类是否调用了父类的构造函数 // 该检查是弱检查,假如调用的代码被注释了,同样能检查成功(这个特性可用于知道建议调用,但是出于某些原因不想调用的情况) function checkBaseConstructorCall(targetClass, classname) { var code = targetClass.toString(); if (!/this\.callBase/.test(code)) { throw new Error(classname + ' : 类构造函数没有调用父类的构造函数!为了安全,请调用父类的构造函数'); } } var KITY_INHERIT_FLAG = '__KITY_INHERIT_FLAG_' + (+new Date()); function inherit(constructor, BaseClass, classname) { var KityClass = eval('(function ' + classname + '( __inherit__flag ) {' + 'if( __inherit__flag != KITY_INHERIT_FLAG ) {' + 'KityClass.__KityConstructor.apply(this, arguments);' + '}' + 'this.__KityClassName = KityClass.__KityClassName;' + '})'); KityClass.__KityConstructor = constructor; KityClass.prototype = new BaseClass(KITY_INHERIT_FLAG); for (var methodName in BaseClass.prototype) { if (BaseClass.prototype.hasOwnProperty(methodName) && methodName.indexOf('__Kity') !== 0) { KityClass.prototype[methodName] = BaseClass.prototype[methodName]; } } KityClass.prototype.constructor = KityClass; return KityClass; } function mixin(NewClass, mixins) { if (false === mixins instanceof Array) { return NewClass; } var i, length = mixins.length, proto, method; NewClass.__KityMixins = { constructor: [] }; for (i = 0; i < length; i++) { proto = mixins[i].prototype; for (method in proto) { if (false === proto.hasOwnProperty(method) || method.indexOf('__Kity') === 0) { continue; } if (method === 'constructor') { // constructor 特殊处理 NewClass.__KityMixins.constructor.push(proto[method]); } else { NewClass.prototype[method] = NewClass.__KityMixins[method] = proto[method]; } } } return NewClass; } function extend(BaseClass, extension) { if (extension.__KityClassName) { extension = extension.prototype; } for (var methodName in extension) { if (extension.hasOwnProperty(methodName) && methodName.indexOf('__Kity') && methodName != 'constructor') { var method = BaseClass.prototype[methodName] = extension[methodName]; method.__KityMethodClass = BaseClass; method.__KityMethodName = methodName; } } return BaseClass; } /** * @method kity.createClass() * @grammar kity.createClass(classname, defines) => {Class} * @description 创建一个类 * @param {string} classname 类名,用于调试的时候查看,可选 * @param {object} defines 类定义 * defines.base {Class} * 定义的类的基类,如果不配置,则表示基类为 kity.Class * defines.mixins {Class[]} * 定义的类要融合的类列表 * defines.constructor {Function} * 定义类的构造函数,如果父类显式定义了构造函数,需要在构造函数中使用 callBase() 方法调用父类的构造函数 * defines.* {Function} * 定义类的其它函数 * * @example 创建一个类 * * ```js * var Animal = kity.createClass('Animal', { * constructor: function(name) { * this.name = name; * }, * toString: function() { * return this.name; * } * }); * * var a = new Animal('kity'); * console.log(a.toString()); // "kity" * ``` * * @example 继承一个类 * * ```js * var Cat = kity.createClass('Cat', { * base: Animal, * constructor: function(name, color) { * // 调用父类构造函数 * this.callBase(name); * }, * toString: function() { * return 'A ' + this.color + ' cat, ' + this.callBase(); * } * }); * * var cat = new Cat('kity', 'black'); * console.log(cat.toString()); // "A black cat, kity" * ``` * * @example 混合类的能力 * ```js * var Walkable = kity.createClass('Walkable', { * constructor: function() { * this.speed = 'fast'; * }, * walk: function() { * console.log('I am walking ' + this.speed); * } * }); * * var Dog = kity.createClass('Dog', { * base: Animal, * mixins: [Walkable], * constructor: function(name) { * this.callBase(name); * this.callMixins(); * } * }); * * var dog = new Dog('doggy'); * console.log(dog.toString() + ' say:'); * dog.walk(); * ``` */ exports.createClass = function(classname, defines) { var constructor, NewClass, BaseClass; if (arguments.length === 1) { defines = arguments[0]; classname = 'AnonymousClass'; } BaseClass = defines.base || Class; if (defines.hasOwnProperty('constructor')) { constructor = defines.constructor; if (BaseClass != Class) { checkBaseConstructorCall(constructor, classname); } } else { constructor = function() { this.callBase.apply(this, arguments); this.callMixin.apply(this, arguments); }; } NewClass = inherit(constructor, BaseClass, classname); NewClass = mixin(NewClass, defines.mixins); NewClass.__KityClassName = constructor.__KityClassName = classname; NewClass.__KityBaseClass = constructor.__KityBaseClass = BaseClass; NewClass.__KityMethodName = constructor.__KityMethodName = 'constructor'; NewClass.__KityMethodClass = constructor.__KityMethodClass = NewClass; // 下面这些不需要拷贝到原型链上 delete defines.mixins; delete defines.constructor; delete defines.base; NewClass = extend(NewClass, defines); return NewClass; }; /** * @method kity.extendClass() * @grammar kity.extendClass(clazz, extension) => {Class} * @description 拓展一个已有的类 * * @example * * ```js * kity.extendClass(Dog, { * spark: function() { * console.log('wao wao wao!'); * } * }); * * new Dog().spark(); // "wao wao wao!"; * ``` */ exports.extendClass = extend; });