blob: 815132f99e169d8767b14ef92fb602c00a62d0e7 [file] [log] [blame]
/**
* @file 面向对象 类 的实现工具
* 主要修改自大佛chris(wfsr@foxmail.com)的moye。
*/
define(function (require, exports) {
var base = require('./base');
var PRIVATE_AREA_KEY = '\x0E\x0EprivateProps';
/**
* 创建新类。
* prototype中:
* _applySuper、_superClass 为内置属性禁止覆盖。
* _define、_construct为特定功用属性,供用户override。
* 不支持自定义类似C++/Java的“自动执行父类构造函数”(因为事实上不是必须,并易引起使用者关于override的某些困惑)。
* 构造时须执行的逻辑,可在porototype._construct中传入。
* prototype._construct可继承。
* 不自动调用父类的_construct,如需要可手动用this._applySuper('_construct')(不要使用SuperClass(this)的方式)。
*
* @param {Object} prototype 类的原型对象
* @return {Function} 新类构造函数
*/
exports.newClass = function (prototype) {
var Class = function () {
return isFunction(this._construct)
? this._construct.apply(this, arguments)
: this;
};
Class.extend = extend;
Class.implement = implement;
attrCopy(Class.defineProperties = {}, prototype._define);
prototype._define = null;
Class.implement(prototype);
Class.uid = 'Class_' + base.localUID();
Class.prototype._prop = prop;
return Class;
};
/**
* 调用父类方法。
* 使用方法:this._applySuper('_someMethod', arguments)
*
* @protected
* @final
* @param {string} name 父类方法名
* @param {Array...} ... 其他参数数组。
* 用数组的形式,是为了调用起来比较方便,很多场景下需要把所有参数都传给super。
*/
function applySuper(name, args) {
var SuperClass = this.constructor;
var thisMethod = this[name];
var method;
// 向祖先找到第一个和thisMethod不一样的method
// 如果不这么做,则可能导致死循环,例如:
// 类A有方法f,
// 类B继承类A,override方法f,f中有调用applySuper('f'),
// 类C继承类B,没有override方法f,
// 则类C的实例调用f时,死循环(因为applySuper中得到的super永远是B)。
while (
(SuperClass = SuperClass.prototype._superClass)
&& (method = SuperClass.prototype[name])
&& method === thisMethod
) {/*jshint noempty:false */}
if (method) {
return method.apply(this, args || []);
}
throw new Error('parent Class has no method named ' + name);
}
/**
* 设置或得到本实例的私有属性。
* 业务代码中一般不需要使用,只有如Component这样的基类中,
* 为了避免子类覆盖父类的私有属性,所以用此方法建立私有的属性域。
*
* @protected
* @final
* @param {string} key 属性名
* @param {*=} value 属性值,缺省则表示要获取属性值
*/
function prop(key, value) {
var privatePropArea = this[PRIVATE_AREA_KEY]
|| (this[PRIVATE_AREA_KEY] = {});
return arguments.length > 1
? (privatePropArea[key] = value)
: privatePropArea[key];
}
/**
* 继承(泛化)生成子类
*
* @inner
* @this {Class} 父类
* @param {Object} prototype 子类的方法集合
* @return {Class} 新的子类
*/
function extend(prototype) {
var SuperClass = this;
var SubClass = exports.newClass(
{_define: SuperClass.defineProperties}
);
var F = function () {};
F.prototype = SuperClass.prototype;
var newSubProto = SubClass.prototype = new F();
attrCopy(SubClass.defineProperties, prototype._define);
prototype._define = null;
SubClass.implement(prototype);
newSubProto._applySuper = applySuper;
newSubProto._superClass = SuperClass;
newSubProto.constructor = SubClass;
return SubClass;
}
/**
* 扩展类方法
*
* @inner
* @this {Class} 要扩展的类
* @param {Object} params 扩展的方法集
* @return {Class} 扩展后的类
*/
function implement(params) {
return attrCopy(this.prototype, params);
}
/**
* @inner
*/
function attrCopy(target, source) {
for (var key in source) {
if (source.hasOwnProperty(key)) {
target[key] = source[key];
}
}
return target;
}
/**
* @inner
*/
function isFunction(o) {
return Object.prototype.toString.call(o) === '[object Function]';
}
/**
* 提供另一种非常简单的面向对象继承,适用于没有用前述newClass生成的类。
* 父类的构造函数需要在子类的构造函数中手动调用,如:SuperClass.apply(this, arguments);
* 会向SubClass.prototype挂_superClass和_applySuper
*
* @public
* @param {Function} SubClass 子类
* @param {Function} SuperClass 父类
* @return {Function} SubClass
*/
exports.simpleInherit = function (SubClass, SuperClass) {
var oriSubProto = SubClass.prototype;
var Clz = new Function(); // jshint ignore:line
Clz.prototype = SuperClass.prototype;
var newSubProto = SubClass.prototype = new Clz();
attrCopy(newSubProto, oriSubProto);
newSubProto._applySuper = applySuper;
newSubProto._superClass = SuperClass;
newSubProto.constructor = SubClass;
return SubClass;
};
return exports;
});