@jswork/next
Version:
A javascript OOP toolkit for mobile & modern web.
580 lines (515 loc) • 15.6 kB
JavaScript
(function() {
/** Detect free variable `global` from Node.js. */
var freeGlobal =
typeof global == 'object' && global && global.Object === Object && global;
/** Detect free variable `self`. */
var freeSelf =
typeof self == 'object' && self && self.Object === Object && self;
/** Used as a reference to the global object. */
var root = freeGlobal || freeSelf || Function('return this')();
/** Detect free variable `exports`. */
var freeExports =
typeof exports == 'object' && exports && !exports.nodeType && exports;
/** Detect free variable `module`. */
var freeModule =
freeExports &&
typeof module == 'object' &&
module &&
!module.nodeType &&
module;
//force inject to global:
var nx = (root.nx = root.nx || {
BREAKER: {},
NIL: {},
VERSION: '1.3.4',
DEBUG: false,
GLOBAL: root
});
// Some AMD build optimizers, like r.js, check for condition patterns like:
if (
typeof define == 'function' &&
typeof define.amd == 'object' &&
define.amd
) {
root.nx = nx;
// Define as an anonymous module so, through path mapping, it can be
// referenced as the "underscore" module.
define(function () {
return nx;
});
}
// Check for `exports` after `define` in case a build optimizer adds it.
else if (freeModule) {
// Export for Node.js.
freeModule.exports = nx;
freeModule.exports.default = nx; // 添加默认导出
freeModule.exports.nx = nx;
// Export for CommonJS support.
freeExports.nx = nx;
} else {
// Export to the global object.
root.nx = nx;
}
(function () {
var DOT = '.';
var NUMBER = 'number';
var UNDEF = 'undefined';
var ARRAY_PROTO = Array.prototype;
var toString = Object.prototype.toString;
var hasOwn = Object.prototype.hasOwnProperty;
var INDEXES_PATH_RE = /\[(\w+)\]/g;
var MULTIPLE_DOT_RE = /[.]+/g;
var EDGE_DOT_RE = /^\.|\.$/g;
var POS1 = '.$1';
var EMP = '';
var normalize = function (path) {
return path
.toString()
.replace(INDEXES_PATH_RE, POS1)
.replace(MULTIPLE_DOT_RE, DOT)
.replace(EDGE_DOT_RE, EMP);
};
nx.noop = function () {};
nx.typeof = function (inTarget) {
if (inTarget === null) return 'null';
if (inTarget === undefined) return 'undefined';
var isPrimitive = typeof inTarget !== 'object';
if (!isPrimitive) return toString.call(inTarget).slice(8, -1).toLowerCase();
return typeof inTarget;
};
nx.stubTrue = function () {
return true;
};
nx.stubFalse = function () {
return false;
};
nx.stubValue = function (inValue) {
return inValue;
};
nx.stubPromise = function (inValue) {
if (typeof inValue === 'undefined') return Promise.resolve();
return Promise.resolve(inValue);
};
nx.isBoolean = function (inTarget) {
return typeof inTarget === 'boolean';
};
nx.isString = function (inTarget) {
return typeof inTarget === 'string';
};
nx.isNumber = function (inTarget) {
return typeof inTarget === NUMBER && !isNaN(inTarget);
};
nx.isNaN = function (inTarget) {
return isNaN(inTarget);
};
nx.isFunction = function (inTarget) {
return typeof inTarget === 'function';
};
nx.isNil = function (inTarget) {
return inTarget == null;
};
nx.isArray = function (inTarget) {
return Array.isArray(inTarget);
};
nx.isObject = function (inTarget) {
if (Array.isArray(inTarget)) return false;
return typeof inTarget === 'object' && inTarget !== null;
};
nx.isThenable = function (inTarget) {
if (!inTarget) return false;
return typeof inTarget === 'object' && typeof inTarget.then === 'function';
};
nx.error = function (inMsg) {
throw new Error(inMsg);
};
nx.try = function (inFn, inCatch) {
var cb = inCatch || nx.noop;
try {
inFn();
} catch (err) {
cb(err);
}
};
nx.forEach = function (inArray, inCallback, inContext) {
var length = inArray.length;
var i;
var result;
for (i = 0; i < length; i++) {
result = inCallback.call(inContext, inArray[i], i, inArray);
if (result === nx.BREAKER) {
break;
}
}
};
nx.forIn = function (inObject, inCallback, inContext) {
var key;
var result;
for (key in inObject) {
if (hasOwn.call(inObject, key)) {
result = inCallback.call(inContext, key, inObject[key], inObject);
if (result === nx.BREAKER) {
break;
}
}
}
};
nx.each = function (inTarget, inCallback, inContext) {
var key, length;
var iterator = function (inKey, inValue, inIsArray) {
return (
inCallback.call(inContext, inKey, inValue, inTarget, inIsArray) ===
nx.BREAKER
);
};
if (inTarget) {
length = inTarget.length;
if (typeof length === NUMBER) {
for (key = 0; key < length; key++) {
if (iterator(key, inTarget[key], true)) {
break;
}
}
} else {
for (key in inTarget) {
if (hasOwn.call(inTarget, key)) {
if (iterator(key, inTarget[key], false)) {
break;
}
}
}
}
}
};
nx.map = function (inTarget, inCallback, inContext) {
console.warn('@deprecated: nx.map is deprecated, use array.reduce instead');
var result = [];
nx.each(inTarget, function () {
var item = inCallback.apply(inContext, arguments);
if (item !== nx.BREAKER) {
result.push(item);
} else {
return nx.BREAKER;
}
});
return result;
};
nx.mix = function (inTarget) {
var target = inTarget || {};
var i, length;
var args = arguments;
for (i = 1, length = args.length; i < length; i++) {
nx.forIn(args[i], function (key, val) {
target[key] = val;
});
}
return target;
};
nx.slice = function (inTarget, inStart, inEnd) {
return ARRAY_PROTO.slice.call(inTarget, inStart, inEnd);
};
nx.set = function (inTarget, inPath, inValue) {
var indexesPath = normalize(inPath);
var paths = indexesPath.split(DOT);
var result = inTarget || nx.GLOBAL;
var len_ = paths.length - 1;
var last = paths[len_];
for (var i = 0; i < len_; i++) {
var path = paths[i];
var target = isNaN(+paths[i + 1]) ? {} : [];
result = result[path] = result[path] || target;
}
result[last] = inValue;
return inTarget;
};
nx.get = function (inTarget, inPath, inValue) {
if (!inPath) return inTarget;
if (Array.isArray(inPath))
return inPath.map(function (path) {
return nx.get(inTarget, path, inValue);
});
var idx = normalize(inPath);
var paths = idx.split(DOT);
var result = inTarget || nx.GLOBAL;
paths.forEach(function (path) {
result = result && result[path];
});
return typeof inValue !== UNDEF && typeof result === UNDEF
? inValue
: result;
};
nx.del = function (inTarget, inPath) {
var indexesPath = normalize(inPath);
var paths = indexesPath.split(DOT);
for (var i = 0; i < paths.length; i++) {
var path = paths[i];
if (i === paths.length - 1) {
if (inTarget == null) return false;
if (typeof inTarget === 'object') delete inTarget[path];
return true;
}
inTarget = inTarget[path];
}
return false;
};
// @url: https://github.com/scopsy/await-to-js
nx.to = function (inPromise) {
return inPromise
.then(function (data) {
return [undefined, data];
})
.catch(function (err) {
return [err, undefined];
});
};
})();
(function() {
var RootClass = function() {};
var classMeta = {
__class_id__: 0,
__type__: 'nx.RootClass',
__base__: Object,
__meta__: {},
__static__: false,
__statics__: {},
__properties__: {},
__methods__: {},
__method_init__: nx.noop,
__static_init__: nx.noop
};
var baseMethods = {
base: function() {
var caller = this.base.caller;
var baseMethod;
if (caller && (baseMethod = caller.__base__)) {
return baseMethod.apply(this, arguments);
}
},
parent: function(inName) {
var isStatic = typeof this.__id__ === 'undefined';
var args = nx.slice(arguments, 1);
var base = isStatic ? this.__base__ : this.__base__.prototype;
var type = this['@' + inName].__type__;
var accessor = ['get', 'set'][args.length];
switch (type) {
case 'method':
return base[inName].apply(this, args);
case 'property':
return base['@' + inName][accessor].apply(this, args);
}
}
};
classMeta.__methods__ = RootClass.prototype = nx.mix(
{
constructor: RootClass,
init: nx.noop,
destroy: nx.noop,
toString: function() {
return '[Class@' + this.__type__ + ']';
}
},
baseMethods
);
//mix && export:
nx.mix(classMeta.__statics__, baseMethods);
nx.mix(RootClass, classMeta);
nx.mix(RootClass, classMeta.__statics__);
nx.RootClass = RootClass;
})();
(function () {
var MEMBER_PREFIX = '@';
var VALUE = 'value';
var COMMA = ',';
nx.defineProperty = function (inTarget, inName, inMeta, inIsStatic) {
var key = MEMBER_PREFIX + inName;
var getter, setter, descriptor;
var value, filed;
var typeOfObject = typeof inMeta === 'object';
var meta = inMeta && typeOfObject ? inMeta : { value: inMeta };
if (VALUE in meta) {
value = meta.value;
filed = '_' + inName;
getter = function () {
return filed in this
? this[filed]
: nx.isFunction(value)
? value.call(this)
: value;
};
setter = function (inValue) {
this[filed] = inValue;
};
} else {
getter = inMeta.get || (inTarget[key] && inTarget[key].get) || nx.noop;
setter = inMeta.set || (inTarget[key] && inTarget[key].set) || nx.noop;
}
//remain base setter/getter:
if (key in inTarget) {
getter.__base__ = inTarget[key].get;
setter.__base__ = inTarget[key].set;
}
descriptor = inTarget[key] = {
__meta__: inMeta,
__name__: inName,
__type__: 'property',
__static__: !!inIsStatic,
get: getter,
set: setter,
configurable: true
};
Object.defineProperty(inTarget, inName, descriptor);
return descriptor;
};
nx.defineMethod = function (inTarget, inName, inMeta, inIsStatic) {
var key = MEMBER_PREFIX + inName;
inTarget[inName] = inMeta;
return (inTarget[key] = {
__meta__: inMeta,
__name__: inName,
__type__: 'method',
__static__: !!inIsStatic
});
};
nx.defineBombMethod = function (inTarget, inName, inMeta, inIsStatic) {
var keys = inName.split(COMMA);
keys.forEach(function (key, index) {
nx.defineMethod(
inTarget,
key,
inMeta.call(inTarget, key, index),
inIsStatic
);
});
};
nx.defineMembers = function (inMember, inTarget, inObject, inIsStatic) {
nx.forIn(inObject, function (key, val) {
var idx = key.indexOf(COMMA);
var hasComma = idx > -1;
if (hasComma) {
nx.defineBombMethod(inTarget, key, val, inIsStatic);
} else {
nx['define' + inMember](inTarget, key, val, inIsStatic);
}
});
};
})();
(function () {
var classId = 1,
instanceId = 0;
var NX_ANONYMOUS = 'nx.Anonymous';
function LifeCycle(inType, inMeta) {
this.type = inType;
this.meta = inMeta;
this.base = inMeta.extends || nx.RootClass;
this.$base = this.base.prototype;
this.__class_meta__ = {};
this.__class__ = null;
this.__constructor__ = null;
}
LifeCycle.prototype = {
constructor: LifeCycle,
initMetaProcessor: function () {
var meta = this.meta;
var methods = meta.methods || {};
var statics = meta.statics || {};
nx.mix(this.__class_meta__, {
__type__: this.type,
__meta__: meta,
__base__: this.base,
__class_id__: classId++,
__method_init__: methods.init || this.base.__method_init__,
__static_init__: statics.init || this.base.__static_init__,
__static__: !meta.methods && !!meta.statics
});
},
createClassProcessor: function () {
var self = this;
this.__class__ = function () {
this.__id__ = instanceId++;
self.__constructor__.apply(this, arguments);
self.registerDebug(this);
};
},
inheritProcessor: function () {
var classMeta = this.__class_meta__;
this.inheritedClass(classMeta);
this.defineMethods(classMeta, true);
this.defineMethods(classMeta, false);
this.defineProperties(classMeta);
},
inheritedClass: function (inClassMeta) {
var SuperClass = function () {};
var Class = this.__class__;
SuperClass.prototype = this.$base;
Class.prototype = new SuperClass();
Class.prototype.$base = this.$base;
Class.prototype.constructor = Class;
},
defineMethods: function (inClassMeta, inIsStatic) {
var key = inIsStatic ? 'statics' : 'methods';
var key_ = '__' + key + '__';
var target = inIsStatic ? this.__class__ : this.__class__.prototype;
var baseTarget = inIsStatic ? this.base : this.base.prototype;
var methods = baseTarget[key_] || {};
nx.forIn(this.meta[key], function (key, value) {
if (methods[key] && typeof value === 'function') {
value.__base__ = methods[key];
}
});
target[key_] = nx.mix(inClassMeta[key_], methods, this.meta[key]);
nx.defineMembers('Method', target, target[key_], inIsStatic);
},
defineProperties: function (inClassMeta) {
var isStatic = inClassMeta.__static__;
var target = isStatic ? this.__class__ : this.__class__.prototype;
var baseTarget = isStatic ? this.base : this.base.prototype;
target.__properties__ = nx.mix(
null,
baseTarget.__properties__,
inClassMeta.__properties__,
this.meta.properties
);
nx.defineMembers('Property', target, target.__properties__, isStatic);
},
methodsConstructorProcessor: function () {
var classMeta = this.__class_meta__;
this.__constructor__ = function () {
classMeta.__method_init__.apply(this, arguments);
};
},
staticsConstructorProcessor: function () {
var classMeta = this.__class_meta__;
classMeta.__static_init__.call(this.__class__);
},
registerProcessor: function () {
var Class = this.__class__;
var type = this.type;
var classMeta = this.__class_meta__;
nx.mix(Class.prototype, classMeta);
nx.mix(Class, classMeta);
if (type.indexOf(NX_ANONYMOUS) === -1) {
nx.set(nx.GLOBAL, type, Class);
}
},
registerDebug: function (inInstance) {
if (nx.DEBUG) {
nx.set(nx, '__instances__.' + (instanceId - 1), inInstance);
nx.set(nx, '__instances__.length', instanceId);
}
}
};
nx.define = function (inType, inMeta) {
var type = typeof inType === 'string' ? inType : NX_ANONYMOUS + classId;
var meta = inMeta || inType;
var lifeCycle = new LifeCycle(type, meta);
lifeCycle.initMetaProcessor();
lifeCycle.createClassProcessor();
lifeCycle.inheritProcessor();
lifeCycle.methodsConstructorProcessor();
lifeCycle.staticsConstructorProcessor();
lifeCycle.registerProcessor();
return lifeCycle.__class__;
};
// todo: will remove this in next version.
nx.declare = nx.define;
})();
}.call(this));