ismart-doc
Version:
API documentation generator,base in https://github.com/mhbseal/modoc
426 lines (400 loc) • 11 kB
JavaScript
/**
* 一些底层的方法
*
* @author hbmu
* @date 2015/2/3
*
* @name common
* @example
* var foo, obj1, obj2, obj3;
*
* function Foo () {
* this.a = 1
* };
* Foo.prototype.b = 2;
* foo = new Foo();
*
* obj1 = {
* a: 1,
* b: 2,
* toString: 3,
* isPrototypeOf: 4,
* constructor: 5
* };
* obj2 = {
* b: 22,
* c: {
* d: 6
* }
* };
* obj3 = {
* c: {
* e: 7,
* f: {
* g: 8,
* h: 9
* }
* }
* };
*/
define(function () {
"use strict";
var
common = {},
class2type = {},
Ctor = function() {},
ArrayProto = Array.prototype,
StrProto = String.prototype,
ObjProto = Object.prototype,
nativeTrim = StrProto.trim,
nativeKeys = Object.keys,
toString = ObjProto.toString,
hasOwn = ObjProto.hasOwnProperty,
nativeCreate = Object.create,
nativeIsArray = ArrayProto.isArray,
rWord = /[^,| ]+/g, // 分隔符正则
// 在<IE9下,不枚举的bug
hasEnumBug = !{toString: null}.propertyIsEnumerable('toString'),
nonEnumerableProps = ['toString', 'toLocaleString', 'valueOf', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'constructor'];
// 判断数据类型基础方法
function type(obj) {
return typeof obj === 'object' || typeof obj === 'function' ? class2type[toString.call(obj)] : typeof obj;
};
'Boolean Number String Function Date RegExp Object Array'.replace(rWord, function(name) {
var lowerName = name.toLowerCase();
class2type['[object ' + name + ']'] = lowerName; // for common.type method
common['is' + name] = function(obj) {
return type(obj) === lowerName;
};
});
/**
* 判断是否是非继承属性
*
* @name has
* @grammar c.has(obj, key)
* @example
* c.has(foo, 'a') => true
* c.has(foo, 'b') => false
*/
common.has = function(obj, key) {
return hasOwn.call(obj, key);
};
/**
* 兼容 IE8- 下有些不枚举的属性,例如'toString', 'toLocaleString', 'valueOf', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'constructor'
*
* @param {object} obj
* @param {function} iteratee
* - param {..} value
* - param {..} key
* - param {object} forIn的第一个参数obj
* @param {object} iteratee的上下文,可选
*
* @name forIn
* @grammar c.forIn(obj, iteratee[, context])
* @example
* c.forIn(obj1, function(v, k) {
* console.log(k + ':' + v)
* })
* => 依次输出: 'a: 1', 'b: 2', 'toString: 3', 'isPrototypeOf: 4', 'constructor: 5'
*/
common.forIn = function(obj, cb, context) {
for (var key in obj) if (cb.call(context, obj[key], key, obj) === false) return; // normal
if (hasEnumBug) { // nonEnumerableProps
var
index = 0,
len = nonEnumerableProps.length;
for (; index < len; index++) {
if (common.has(obj, nonEnumerableProps[index]) && cb.call(context, obj[nonEnumerableProps[index]], nonEnumerableProps[index], obj) === false) return;
}
}
}
/**
* 合并对象到第一个obj
*
* @param {boolean} 是否深度复制,可选
* @param {object|array} 目标对象
* @params {object|array} 需要extend的对象,可多个参数
* @return {object|array} extend后的object
*
* @name extend
* @grammar c.extend([isDeep,] obj1, obj2, obj3...)
* @example
* c.extend(obj1, obj2) => {a: 1, b: 22, c: {d: 6}, toString: 3, isPrototypeOf: 4, constructor: 5}
* // 浅拷贝
* c.extend(obj2, obj3) => {b: 22, c: {e: 7, f: {g: 8, h: 9}}}
* // 深度拷贝
* c.extend(true, obj1, obj2, obj3)
* => {a: 1, b: 22, c: {d: 6, e: 7, f: {g: 8, h: 9}}, toString: 3, isPrototypeOf: 4, constructor: 5}
*/
common.extend = function() {
var
src, source, deep, srcType, copyType, clone, copyIsArray,
index = 1,
args = arguments,
len = args.length,
target = args[0];
// 校正参数
deep = typeof target === 'boolean';
if (deep) {
index++;
target = args[1];
}
// 如果只有一个参数,直接合并到调用的对象上
if (index === len) {
target = this;
index--;
}
for (; index < len; index++) {
source = arguments[index]; // 需要extend的参数
if (source != null) {
this.forIn(source, function(copy, prop) {
src = target[prop];
// 防止循环引用
if (target === copy) {
return false;
}
if (deep && (copyType = copy && type(copy)) && (copyType === 'object' && this.has(source, prop) || (copyIsArray = copyType === 'array'))) { // 深拷贝
srcType = src && type(src);
if (copyIsArray) {
copyIsArray = false;
clone = srcType === 'array' ? src : [];
} else {
clone = srcType === 'object' ? src : {};
}
target[prop] = this.extend(deep, clone, copy);
} else { // 浅拷贝
if (copy !== undefined) {
target[prop] = copy;
}
}
}, this)
}
}
return target;
};
common.extend({
/**
* 判断对象的类型
*
* @name type
* @grammar c.type(*)
* @example
* c.type({a: 1}) => 'object'
* c.type('mojs') => 'string'
* c.type(2) => 'number'
*/
type: function(obj) {
if (obj == null) {
return obj + '';
}
return type(obj);
},
/**
* 是否是Boolean类型
*
* @name isBoolean
* @grammar c.isBoolean(*)
* @example
* c.isBoolean({a: 1}) => false
*/
/**
* 是否是Number类型
*
* @name isNumber
* @grammar c.isNumber(*)
*/
/**
* 是否是String类型
*
* @name isString
* @grammar c.isString(*)
*/
/**
* 是否是Function类型
*
* @name isFunction
* @grammar c.isFunction(*)
*/
/**
* 是否是Date类型
*
* @name isDate
* @grammar c.isDate(*)
*/
/**
* 是否是RegExp类型
*
* @name isRegExp
* @grammar c.isRegExp(*)
*/
/**
* 是否是Object类型
*
* @name isObject
* @grammar c.isObject(*)
*/
/**
* 是否是数组
*
* @name isArray
* @grammar c.isArray(*)
*/
isArray: nativeIsArray || function(obj) {
return type(obj) === 'array';
},
/**
* 是否是类数组, 例如nodelist,arguments,具有length并且keys为0.1.2...的obj
*
* @name isArraylike
* @grammar c.isArraylike(*)
* @example
* c.isArraylike([1, 2, 3]) => true
* c.isArraylike({1: 1, 2: 2, 3: 3, length: 3}) => true
* c.isArraylike({1: 1, 2: 2, 3: 3}) => false
*/
isArraylike: function(obj) {
var
len = obj.length,
type = this.type(obj);
return !!len || type === 'array' || typeof len === 'number' && len > 0 && (len - 1) in obj || len === 0;
},
/**
* 判断是否为NaN
*
* @name isNaN
* @grammar c.isNaN(*)
* @example
* c.isNaN(NaN) => true
* c.isNaN(undefined) => false
*/
isNaN: function(obj) {
return obj === undefined ? false : isNaN(obj);
},
/**
* 返回obj的长度
*
* @name size
* @grammar c.size(obj)
* @example
* c.size([1, 2, 3]) => 3
* c.size({a: 1, b: 2}) => 2
*/
size: function(obj) {
if (obj == null) return 0;
return this.isArraylike(obj) ? obj.length : this.keys(obj).length;
},
/**
* 去掉字符串前后的空
* @name trim
* @grammar c.trim(text)
* @example
* c.trim(' abc defg ') => 'abc defg'
*/
trim: function(text) {
if (nativeTrim) return nativeTrim.call(text);
text.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
},
/**
* 获取对象的key集合
*
* @name keys
* @grammar c.keys(obj)
* @example
* c.keys({a: 1, b: 2}) => ['a', 'b']
*/
keys: function(obj) {
var
keys;
if (nativeKeys) return nativeKeys(obj);
keys = [];
this.forIn(obj, function(value, key) {
if (this.has(obj, key)) keys.push(key);
})
return keys;
},
/**
* 当前时间戳
*
* @name now
* @grammar c.now()
*/
now: Date.now || function() {
return +new Date();
},
/**
* 同console.log()
*
* @name log
* @grammar c.log(*)
*/
log: function() {
window.console && Function.apply.call(console.log, console, arguments);
},
/**
* 同Object.create(prototype)
*
* @param {object} prototype
* @return {object} 原型为参数prototype的对象
*
* @name baseCreate
* @grammar c.baseCreate(prototype)
* @example
* c.baseCreate() => {}
* c.baseCreate({ a: Foo }).a => Foo
*/
baseCreate: function(prototype) {
if (!this.isObject(prototype)) return {};
if (nativeCreate) return nativeCreate(prototype);
Ctor.prototype = prototype;
var result = new Ctor;
Ctor.prototype = null;
return result;
},
/**
* 创建一个构造函数(继承、原型方法都可选,继承可以通过新构造函数的superCtor访问父级构造函数)
*
* @param {function} (子级)构造函数
* @param {object} 原型的方法集,可选
* @param {function} 父级构造函数,可选
* @return {function} 新的构造函数
*
* @name baseClass
* @grammar c.baseClass(subCtor, prototypes, superCtor)
* @example
* c.baseClass(A, {a: function() {}, b: function(){}}, B) => A继承B,并且prototype上添加方法a和b
* c.baseClass(A, {a: function() {}, b: function(){}}) => A的prototype上添加方法a和b
* c.baseClass(A, B) => A继承B
*/
baseClass: function(subCtor, prototypes, superCtor) {
var
noProtos = typeof arguments[1] !== 'object',
Ctor, isInherit;
// 参数校正
if (noProtos) superCtor = prototypes;
// 是否是调用继承
isInherit = superCtor != null;
// 输出的构造函数
Ctor = function() {
if (arguments.length) {
isInherit && superCtor.apply(this, arguments);
subCtor.apply(this, arguments);
} else {
isInherit && superCtor.call(this);
subCtor.call(this);
}
};
// subCtor继承superCtor的prototypes
if (isInherit) {
Ctor.superCtor = superCtor;
Ctor.prototype = common.baseCreate(superCtor.prototype);
Ctor.prototype.constructor = Ctor;
}
// 自定义的prototypes
common.forIn(prototypes, function(prototype, name) {
Ctor.prototype[name] = prototype;
})
return Ctor;
}
});
return common;
});