QWrap简介之:Helper规范
Helper规范是一个很简单轻松的规范,这个在core/js/helper.h.js里有提到。
一个Helper是指同时满足如下条件的一个对象:
1。Helper是一个不带有可枚举proto属性的简单对象(这意味着你可以用for...in...枚举一个Helper中的所有属性和方法)
2。Helper可以拥有属性和方法,但Helper对方法的定义必须满足如下条件:
2.1. Helper的方法必须是静态方法,即内部不能使用this。
2.2. 同一个Helper中的方法的第一个参数必须是相同类型或相同泛型。
也可以分拆成三点来描述:
1。Helper是一个不带有可枚举proto属性的简单对象。 (纯洁)
2。Helper的所有方法必须是静态方法,即内部不能使用this。 (静态)
3。同一个Helper中的方法的第一个参数必须是相同类型或相同泛型。(针对性)
在QWrap中,一个Helper对应的命名空间通常以“H”结尾,对应的js通常以“.h.js”结尾。
例如,QW.StringH是针对String的Helper的命名空间,它对应的js是“js/core/string.h.js”。
对于只满足“纯洁”“静态”特征的对象,也算是泛Helper,命名空间以“U”(util)结尾。
本来Util和Helper应该是继承关系,但是QWrap淡化了这些关系概念。
“纯洁”有什么用?----方便以后for in。----顺便说一下QWrap的一个脆弱:如果有人把Object的原型污染掉了,可能会产生一些隐患。----同学们啦,千万别污染Object的原型。
“静态”有什么用?----方便移植与函数变换。
“针对性”有什么用?----方便分组,以及移植与函数变换。
这里着重说一下“针对性”的意义。
1 方便分组: 针对字符串的很多方法,就放在StringH里,例如trim、byteLen、subByte、encode4Html、encode4Js;而针对Array的,则放在ArrayH里,如forEach、map、filter。
2 这些方法的第一个参数是它针对的变量。StringH里的所有方法的第一个参数都是字符串,而ArrayH里的所有方法的第一个参数都是数组或类数组(ArrayLike)。
3 有了这种针对性,我们就可以找标准(包括理论标准与事实标准)来实现堆砌代码了,例如StringH.contains(s,subStr) ArrayH.contains(arr, obj) NodeH.contains(parentEl,subEl)。同样是contains,它们各有标准、各得其所、互不冲突。
4 让批量转换有了理论依据。
当然,“纯洁”“静态”“针对性”,这三点对于批量转换都很重要。
好的,看几个Helper的实例,来感性的认识下Helper吧:
string.h.js (针对String的Helper)
array.h.js (针对Array的Helper)
function.h.js (针对Function的Helper)
一个Helper是指同时满足如下条件的一个对象:
1。Helper是一个不带有可枚举proto属性的简单对象(这意味着你可以用for...in...枚举一个Helper中的所有属性和方法)
2。Helper可以拥有属性和方法,但Helper对方法的定义必须满足如下条件:
2.1. Helper的方法必须是静态方法,即内部不能使用this。
2.2. 同一个Helper中的方法的第一个参数必须是相同类型或相同泛型。
也可以分拆成三点来描述:
1。Helper是一个不带有可枚举proto属性的简单对象。 (纯洁)
2。Helper的所有方法必须是静态方法,即内部不能使用this。 (静态)
3。同一个Helper中的方法的第一个参数必须是相同类型或相同泛型。(针对性)
在QWrap中,一个Helper对应的命名空间通常以“H”结尾,对应的js通常以“.h.js”结尾。
例如,QW.StringH是针对String的Helper的命名空间,它对应的js是“js/core/string.h.js”。
对于只满足“纯洁”“静态”特征的对象,也算是泛Helper,命名空间以“U”(util)结尾。
本来Util和Helper应该是继承关系,但是QWrap淡化了这些关系概念。
“纯洁”有什么用?----方便以后for in。----顺便说一下QWrap的一个脆弱:如果有人把Object的原型污染掉了,可能会产生一些隐患。----同学们啦,千万别污染Object的原型。
“静态”有什么用?----方便移植与函数变换。
“针对性”有什么用?----方便分组,以及移植与函数变换。
这里着重说一下“针对性”的意义。
1 方便分组: 针对字符串的很多方法,就放在StringH里,例如trim、byteLen、subByte、encode4Html、encode4Js;而针对Array的,则放在ArrayH里,如forEach、map、filter。
2 这些方法的第一个参数是它针对的变量。StringH里的所有方法的第一个参数都是字符串,而ArrayH里的所有方法的第一个参数都是数组或类数组(ArrayLike)。
3 有了这种针对性,我们就可以找标准(包括理论标准与事实标准)来实现堆砌代码了,例如StringH.contains(s,subStr) ArrayH.contains(arr, obj) NodeH.contains(parentEl,subEl)。同样是contains,它们各有标准、各得其所、互不冲突。
4 让批量转换有了理论依据。
当然,“纯洁”“静态”“针对性”,这三点对于批量转换都很重要。
好的,看几个Helper的实例,来感性的认识下Helper吧:
string.h.js (针对String的Helper)
View Code
/**
* @class StringH 核心对象String的扩展
* @singleton
* @namespace QW
* @helper
*/
(function() {
var StringH = {
/**
* 除去字符串两边的空白字符
* @method trim
* @static
* @param {String} s 需要处理的字符串
* @return {String} 除去两端空白字符后的字符串
* @remark 如果字符串中间有很多连续tab,会有有严重效率问题,相应问题可以用下一句话来解决.
return s.replace(/^[\s\xa0\u3000]+/g,"").replace(/([^\u3000\xa0\s])[\u3000\xa0\s]+$/g,"$1");
*/
trim: function(s) {
return s.replace(/^[\s\xa0\u3000]+|[\u3000\xa0\s]+$/g, "");
},
/**
* 对一个字符串进行多次replace
* @method mulReplace
* @static
* @param {String} s 需要处理的字符串
* @param {array} arr 数组,每一个元素都是由replace两个参数组成的数组
* @return {String} 返回处理后的字符串
* @example alert(mulReplace("I like aa and bb. JK likes aa.",[[/aa/g,"山"],[/bb/g,"水"]]));
*/
mulReplace: function(s, arr) {
for (var i = 0; i < arr.length; i++) {
s = s.replace(arr[i][0], arr[i][1]);
}
return s;
},
/**
* 字符串简易模板
* @method format
* @static
* @param {String} s 字符串模板,其中变量以{0} {1}表示
* @param {String} arg0 (Optional) 替换的参数
* @return {String} 模板变量被替换后的字符串
* @example alert(format("{0} love {1}.",'I','You'))
*/
format: function(s, arg0) {
var args = arguments;
return s.replace(/\{(\d+)\}/ig, function(a, b) {
return args[(b | 0) + 1] || '';
});
},
/*
* 字符串简易模板
* @method tmpl
* @static
* @param {String} sTmpl 字符串模板,其中变量以{$aaa}表示
* @param {Object} opts 模板参数
* @return {String} 模板变量被替换后的字符串
* @example alert(tmpl("{$a} love {$b}.",{a:"I",b:"you"}))
tmpl:function(sTmpl,opts){
return sTmpl.replace(/\{\$(\w+)\}/g,function(a,b){return opts[b]});
},
*/
/**
* 字符串模板
* @method tmpl
* @static
* @param {String} sTmpl 字符串模板,其中变量以{$aaa}表示。模板语法:
分隔符为{xxx},"}"之前没有空格字符。
js表达式/js语句里的'}', 需使用' }',即前面有空格字符
{strip}...{/strip}里的所有\r\n打头的空白都会被清除掉
{}里只能使用表达式,不能使用语句,除非使用以下标签
{js ...} --任意js语句, 里面如果需要输出到模板,用print("aaa");
{if(...)} --if语句,写法为{if($a>1)},需要自带括号
{elseif(...)} --elseif语句,写法为{elseif($a>1)},需要自带括号
{else} --else语句,写法为{else}
{/if} --endif语句,写法为{/if}
{for(...)} --for语句,写法为{for(var i=0;i<1;i++)},需要自带括号
{/for} --endfor语句,写法为{/for}
{while(...)} --while语句,写法为{while(i-->0)},需要自带括号
{/while} --endwhile语句, 写法为{/while}
* @param {Object} opts (Optional) 模板参数
* @return {String|Function} 如果调用时传了opts参数,则返回字符串;如果没传,则返回一个function(相当于把sTmpl转化成一个函数)
* @example alert(tmpl("{$a} love {$b}.",{a:"I",b:"you"}));
* @example alert(tmpl("{js print('I')} love {$b}.",{b:"you"}));
*/
tmpl: (function() {
/*
sArrName 拼接字符串的变量名。
*/
var sArrName = "sArrCMX",
sLeft = sArrName + '.push("';
/*
tag:模板标签,各属性含义:
tagG: tag系列
isBgn: 是开始类型的标签
isEnd: 是结束类型的标签
cond: 标签条件
rlt: 标签结果
sBgn: 开始字符串
sEnd: 结束字符串
*/
var tags = {
'js': {
tagG: 'js',
isBgn: 1,
isEnd: 1,
sBgn: '");',
sEnd: ';' + sLeft
},
//任意js语句, 里面如果需要输出到模板,用print("aaa");
'if': {
tagG: 'if',
isBgn: 1,
rlt: 1,
sBgn: '");if',
sEnd: '{' + sLeft
},
//if语句,写法为{if($a>1)},需要自带括号
'elseif': {
tagG: 'if',
cond: 1,
rlt: 1,
sBgn: '");} else if',
sEnd: '{' + sLeft
},
//if语句,写法为{elseif($a>1)},需要自带括号
'else': {
tagG: 'if',
cond: 1,
rlt: 2,
sEnd: '");}else{' + sLeft
},
//else语句,写法为{else}
'/if': {
tagG: 'if',
isEnd: 1,
sEnd: '");}' + sLeft
},
//endif语句,写法为{/if}
'for': {
tagG: 'for',
isBgn: 1,
rlt: 1,
sBgn: '");for',
sEnd: '{' + sLeft
},
//for语句,写法为{for(var i=0;i<1;i++)},需要自带括号
'/for': {
tagG: 'for',
isEnd: 1,
sEnd: '");}' + sLeft
},
//endfor语句,写法为{/for}
'while': {
tagG: 'while',
isBgn: 1,
rlt: 1,
sBgn: '");while',
sEnd: '{' + sLeft
},
//while语句,写法为{while(i-->0)},需要自带括号
'/while': {
tagG: 'while',
isEnd: 1,
sEnd: '");}' + sLeft
} //endwhile语句, 写法为{/while}
};
return function(sTmpl, opts) {
var N = -1,
NStat = []; //语句堆栈;
var ss = [
[/\{strip\}([\s\S]*?)\{\/strip\}/g, function(a, b) {
return b.replace(/[\r\n]\s*\}/g, " }").replace(/[\r\n]\s*/g, "");
}],
[/\\/g, '\\\\'],
[/"/g, '\\"'],
[/\r/g, '\\r'],
[/\n/g, '\\n'], //为js作转码.
[
/\{[\s\S]*?\S\}/g, //js里使用}时,前面要加空格。
function(a) {
a = a.substr(1, a.length - 2);
for (var i = 0; i < ss2.length; i++) {a = a.replace(ss2[i][0], ss2[i][1]); }
var tagName = a;
if (/^(.\w+)\W/.test(tagName)) {tagName = RegExp.$1; }
var tag = tags[tagName];
if (tag) {
if (tag.isBgn) {
var stat = NStat[++N] = {
tagG: tag.tagG,
rlt: tag.rlt
};
}
if (tag.isEnd) {
if (N < 0) {throw new Error("多余的结束标记" + a); }
stat = NStat[N--];
if (stat.tagG != tag.tagG) {throw new Error("标记不匹配:" + stat.tagG + "--" + tagName); }
} else if (!tag.isBgn) {
if (N < 0) {throw new Error("多余的标记" + a); }
stat = NStat[N];
if (stat.tagG != tag.tagG) {throw new Error("标记不匹配:" + stat.tagG + "--" + tagName); }
if (tag.cond && !(tag.cond & stat.rlt)) {throw new Error("标记使用时机不对:" + tagName); }
stat.rlt = tag.rlt;
}
return (tag.sBgn || '') + a.substr(tagName.length) + (tag.sEnd || '');
} else {
return '",(' + a + '),"';
}
}
]
];
var ss2 = [
[/\\n/g, '\n'],
[/\\r/g, '\r'],
[/\\"/g, '"'],
[/\\\\/g, '\\'],
[/\$(\w+)/g, 'opts["$1"]'],
[/print\(/g, sArrName + '.push(']
];
for (var i = 0; i < ss.length; i++) {
sTmpl = sTmpl.replace(ss[i][0], ss[i][1]);
}
if (N >= 0) {throw new Error("存在未结束的标记:" + NStat[N].tagG); }
sTmpl = 'var ' + sArrName + '=[];' + sLeft + sTmpl + '");return ' + sArrName + '.join("");';
//alert('转化结果\n'+sTmpl);
var fun = new Function('opts', sTmpl);
if (arguments.length > 1) {return fun(opts); }
return fun;
};
}()),
/**
* 判断一个字符串是否包含另一个字符串
* @method contains
* @static
* @param {String} s 字符串
* @param {String} opts 子字符串
* @return {String} 模板变量被替换后的字符串
* @example alert(contains("aaabbbccc","ab"))
*/
contains: function(s, subStr) {
return s.indexOf(subStr) > -1;
},
/**
* 全角字符转半角字符
全角空格为12288,转化成" ";
全角句号为12290,转化成".";
其他字符半角(33-126)与全角(65281-65374)的对应关系是:均相差65248
* @method dbc2sbc
* @static
* @param {String} s 需要处理的字符串
* @return {String} 返回转化后的字符串
* @example
var s="发票号是BBC123456,发票金额是12.35元";
alert(dbc2sbc(s));
*/
dbc2sbc: function(s) {
return StringH.mulReplace(s, [
[/[\uff01-\uff5e]/g, function(a) {
return String.fromCharCode(a.charCodeAt(0) - 65248);
}],
[/\u3000/g, ' '],
[/\u3002/g, '.']
]);
},
/**
* 得到字节长度
* @method byteLen
* @static
* @param {String} s 字符串
* @return {number} 返回字节长度
*/
byteLen: function(s) {
return s.replace(/[^\x00-\xff]/g, "--").length;
},
/**
* 得到指定字节长度的子字符串
* @method subByte
* @static
* @param {String} s 字符串
* @param {number} len 字节长度
* @param {string} tail (Optional) 结尾字符串
* @return {string} 返回指定字节长度的子字符串
*/
subByte: function(s, len, tail) {
if (StringH.byteLen(s) <= len) {return s; }
tail = tail || '';
len -= StringH.byteLen(tail);
return s.substr(0, len).replace(/([^\x00-\xff])/g, "$1 ") //双字节字符替换成两个
.substr(0, len) //截取长度
.replace(/[^\x00-\xff]$/, "") //去掉临界双字节字符
.replace(/([^\x00-\xff]) /g, "$1") + tail; //还原
},
/**
* 驼峰化字符串。将“ab-cd”转化为“abCd”
* @method camelize
* @static
* @param {String} s 字符串
* @return {String} 返回转化后的字符串
*/
camelize: function(s) {
return s.replace(/\-(\w)/ig, function(a, b) {
return b.toUpperCase();
});
},
/**
* 反驼峰化字符串。将“abCd”转化为“ab-cd”。
* @method decamelize
* @static
* @param {String} s 字符串
* @return {String} 返回转化后的字符串
*/
decamelize: function(s) {
return s.replace(/[A-Z]/g, function(a) {
return "-" + a.toLowerCase();
});
},
/**
* 字符串为javascript转码
* @method encode4Js
* @static
* @param {String} s 字符串
* @return {String} 返回转化后的字符串
* @example
var s="my name is \"JK\",\nnot 'Jack'.";
window.setTimeout("alert('"+encode4Js(s)+"')",10);
*/
encode4Js: function(s) {
return StringH.mulReplace(s, [
[/\\/g, "\\u005C"],
[/"/g, "\\u0022"],
[/'/g, "\\u0027"],
[/\//g, "\\u002F"],
[/\r/g, "\\u000A"],
[/\n/g, "\\u000D"],
[/\t/g, "\\u0009"]
]);
},
/**
* 为http的不可见字符、不安全字符、保留字符作转码
* @method encode4Http
* @static
* @param {String} s 字符串
* @return {String} 返回处理后的字符串
*/
encode4Http: function(s) {
return s.replace(/[\u0000-\u0020\u0080-\u00ff\s"'#\/\|\\%<>\[\]\{\}\^~;\?\:@=&]/, function(a) {
return encodeURIComponent(a);
});
},
/**
* 字符串为Html转码
* @method encode4Html
* @static
* @param {String} s 字符串
* @return {String} 返回处理后的字符串
* @example
var s="<div>dd";
alert(encode4Html(s));
*/
encode4Html: function(s) {
var el = document.createElement('pre'); //这里要用pre,用div有时会丢失换行,例如:'a\r\n\r\nb'
var text = document.createTextNode(s);
el.appendChild(text);
return el.innerHTML;
},
/**
* 字符串为Html的value值转码
* @method encode4HtmlValue
* @static
* @param {String} s 字符串
* @return {String} 返回处理后的字符串
* @example:
var s="<div>\"\'ddd";
alert("<input value='"+encode4HtmlValue(s)+"'>");
*/
encode4HtmlValue: function(s) {
return StringH.encode4Html(s).replace(/"/g, """).replace(/'/g, "'");
},
/**
* 与encode4Html方法相反,进行反编译
* @method decode4Html
* @static
* @param {String} s 字符串
* @return {String} 返回处理后的字符串
*/
decode4Html: function(s) {
var div = document.createElement('div');
div.innerHTML = StringH.stripTags(s);
return div.childNodes[0] ? div.childNodes[0].nodeValue || '' : '';
},
/**
* 将所有tag标签消除,即去除<tag>,以及</tag>
* @method stripTags
* @static
* @param {String} s 字符串
* @return {String} 返回处理后的字符串
*/
stripTags: function(s) {
return s.replace(/<[^>]*>/gi, '');
},
/**
* eval某字符串。如果叫"eval",在这里需要加引号,才能不影响YUI压缩。不过其它地方用了也会有问题,所以改名evalJs,
* @method evalJs
* @static
* @param {String} s 字符串
* @param {any} opts 运行时需要的参数。
* @return {any} 根据字符结果进行返回。
*/
evalJs: function(s, opts) { //如果用eval,在这里需要加引号,才能不影响YUI压缩。不过其它地方用了也会有问题,所以改成evalJs,
return new Function("opts", s)(opts);
},
/**
* eval某字符串,这个字符串是一个js表达式,并返回表达式运行的结果
* @method evalExp
* @static
* @param {String} s 字符串
* @param {any} opts eval时需要的参数。
* @return {any} 根据字符结果进行返回。
*/
evalExp: function(s, opts) {
return new Function("opts", "return (" + s + ");")(opts);
}
};
QW.StringH = StringH;
}());
array.h.js (针对Array的Helper)
View Code
/**
* @class ArrayH 核心对象Array的扩展
* @singleton
* @namespace QW
* @helper
*/
(function() {
var ArrayH = {
/**
* 在数组中的每个项上运行一个函数,并将全部结果作为数组返回。
* @method map
* @static
* @param {Array} arr 待处理的数组.
* @param {Function} callback 需要执行的函数.
* @param {Object} pThis (Optional) 指定callback的this对象.
* @return {Array} 返回满足过滤条件的元素组成的新数组
* @example
var arr=["aa","ab","bc"];
var arr2=map(arr,function(a,b){return a.substr(0,1)=="a"});
alert(arr2);
*/
map: function(arr, callback, pThis) {
var len = arr.length;
var rlt = new Array(len);
for (var i = 0; i < len; i++) {
if (i in arr) {
rlt[i] = callback.call(pThis, arr[i], i, arr);
}
}
return rlt;
},
/**
* 对Array的每一个元素运行一个函数。
* @method forEach
* @static
* @param {Array} arr 待处理的数组.
* @param {Function} callback 需要执行的函数.
* @param {Object} pThis (Optional) 指定callback的this对象.
* @return {void}
* @example
var arr=["a","b","c"];
var dblArr=[];
forEach(arr,function(a,b){dblArr.push(b+":"+a+a);});
alert(dblArr);
*/
forEach: function(arr, callback, pThis) {
for (var i = 0, len = arr.length; i < len; i++) {
if (i in arr) {
callback.call(pThis, arr[i], i, arr);
}
}
},
/**
* 在数组中的每个项上运行一个函数,并将函数返回真值的项作为数组返回。
* @method filter
* @static
* @param {Array} arr 待处理的数组.
* @param {Function} callback 需要执行的函数.
* @param {Object} pThis (Optional) 指定callback的this对象.
* @return {Array} 返回满足过滤条件的元素组成的新数组
* @example
var arr=["aa","ab","bc"];
var arr2=filter(arr,function(a,b){return a.substr(0,1)=="a"});
alert(arr2);
*/
filter: function(arr, callback, pThis) {
var rlt = [];
for (var i = 0, len = arr.length; i < len; i++) {
if ((i in arr) && callback.call(pThis, arr[i], i, arr)) {
rlt.push(arr[i]);
}
}
return rlt;
},
/**
* 判断数组中是否有元素满足条件。
* @method some
* @static
* @param {Array} arr 待处理的数组.
* @param {Function} callback 需要执行的函数.
* @param {Object} pThis (Optional) 指定callback的this对象.
* @return {boolean} 如果存在元素满足条件,则返回true.
* @example
var arr=["aa","ab","bc"];
var arr2=filter(arr,function(a,b){return a.substr(0,1)=="a"});
alert(arr2);
*/
some: function(arr, callback, pThis) {
for (var i = 0, len = arr.length; i < len; i++) {
if (i in arr && callback.call(pThis, arr[i], i, arr)) {
return true;
}
}
return false;
},
/**
* 判断数组中所有元素都满足条件。
* @method every
* @static
* @param {Array} arr 待处理的数组.
* @param {Function} callback 需要执行的函数.
* @param {Object} pThis (Optional) 指定callback的this对象.
* @return {boolean} 所有元素满足条件,则返回true.
* @example
var arr=["aa","ab","bc"];
var arr2=filter(arr,function(a,b){return a.substr(0,1)=="a"});
alert(arr2);
*/
every: function(arr, callback, pThis) {
for (var i = 0, len = arr.length; i < len; i++) {
if (i in arr && !callback.call(pThis, arr[i], i, arr)) {
return false;
}
}
return true;
},
/**
* 返回一个元素在数组中的位置(从前往后找)。如果数组里没有该元素,则返回-1
* @method indexOf
* @static
* @param {Array} arr 待处理的数组.
* @param {Object} obj 元素,可以是任何类型
* @param {int} fromIdx (Optional) 从哪个位置开始找起,如果为负,则表示从length+startIdx开始找
* @return {int} 则返回该元素在数组中的位置.
* @example
var arr=["a","b","c"];
alert(indexOf(arr,"c"));
*/
indexOf: function(arr, obj, fromIdx) {
var len = arr.length;
fromIdx |= 0; //取整
if (fromIdx < 0) {
fromIdx += len;
}
if (fromIdx < 0) {
fromIdx = 0;
}
for (; fromIdx < len; fromIdx++) {
if (fromIdx in arr && arr[fromIdx] === obj) {
return fromIdx;
}
}
return -1;
},
/**
* 返回一个元素在数组中的位置(从后往前找)。如果数组里没有该元素,则返回-1
* @method lastIndexOf
* @static
* @param {Array} arr 待处理的数组.
* @param {Object} obj 元素,可以是任何类型
* @param {int} fromIdx (Optional) 从哪个位置开始找起,如果为负,则表示从length+startIdx开始找
* @return {int} 则返回该元素在数组中的位置.
* @example
var arr=["a","b","a"];
alert(lastIndexOf(arr,"a"));
*/
lastIndexOf: function(arr, obj, fromIdx) {
var len = arr.length;
fromIdx |= 0; //取整
if (!fromIdx || fromIdx >= len) {
fromIdx = len - 1;
}
if (fromIdx < 0) {
fromIdx += len;
}
for (; fromIdx > -1; fromIdx--) {
if (fromIdx in arr && arr[fromIdx] === obj) {
return fromIdx;
}
}
return -1;
},
/**
* 判断数组是否包含某元素
* @method contains
* @static
* @param {Array} arr 待处理的数组.
* @param {Object} obj 元素,可以是任何类型
* @return {boolean} 如果元素存在于数组,则返回true,否则返回false
* @example
var arr=["a","b","c"];
alert(contains(arr,"c"));
*/
contains: function(arr, obj) {
return (ArrayH.indexOf(arr, obj) >= 0);
},
/**
* 清空一个数组
* @method clear
* @static
* @param {Array} arr 待处理的数组.
* @return {void}
*/
clear: function(arr) {
arr.length = 0;
},
/**
* 将数组里的某(些)元素移除。
* @method remove
* @static
* @param {Array} arr 待处理的数组.
* @param {Object} obj0 待移除元素
* @param {Object} obj1 … 待移除元素
* @return {number} 返回第一次被移除的位置。如果没有任何元素被移除,则返回-1.
* @example
var arr=["a","b","c"];
remove(arr,"a","c");
alert(arr);
*/
remove: function(arr, obj) {
var idx = -1;
for (var i = 1; i < arguments.length; i++) {
var oI = arguments[i];
for (var j = 0; j < arr.length; j++) {
if (oI === arr[j]) {
if (idx < 0) {
idx = j;
}
arr.splice(j--, 1);
}
}
}
return idx;
},
/**
* 数组元素除重,得到新数据
* @method unique
* @static
* @param {Array} arr 待处理的数组.
* @return {void} 数组元素除重,得到新数据
* @example
var arr=["a","b","a"];
alert(unique(arr));
*/
unique: function(arr) {
var rlt = [],
oI = null,
indexOf = Array.IndexOf || ArrayH.indexOf;
for (var i = 0, len = arr.length; i < len; i++) {
if (indexOf(rlt, oI = arr[i]) < 0) {
rlt.push(oI);
}
}
return rlt;
},
/**
* 为数组元素进行递推操作。
* @method reduce
* @static
* @param {Array} arr 待处理的数组.
* @param {Function} callback 需要执行的函数。
* @param {any} initial (Optional) 初始值,如果没有这初始,则从第一个有效元素开始。没有初始值,并且没有有效元素,会抛异常
* @return {any} 返回递推结果.
* @example
var arr=[1,2,3];
alert(reduce(arr,function(a,b){return Math.max(a,b);}));
*/
reduce: function(arr, callback, initial) {
var len = arr.length;
var i = 0;
if (arguments.length < 3) { //找到第一个有效元素当作初始值
var hasV = 0;
for (; i < len; i++) {
if (i in arr) {
initial = arr[i++];
hasV = 1;
break;
}
}
if (!hasV) {throw new Error("No component to reduce"); }
}
for (; i < len; i++) {
if (i in arr) {
initial = callback(initial, arr[i], i, arr);
}
}
return initial;
},
/**
* 为数组元素进行逆向递推操作。
* @method reduceRight
* @static
* @param {Array} arr 待处理的数组.
* @param {Function} callback 需要执行的函数。
* @param {any} initial (Optional) 初始值,如果没有这初始,则从第一个有效元素开始。没有初始值,并且没有有效元素,会抛异常
* @return {any} 返回递推结果.
* @example
var arr=[1,2,3];
alert(reduceRight(arr,function(a,b){return Math.max(a,b);}));
*/
reduceRight: function(arr, callback, initial) {
var len = arr.length;
var i = len - 1;
if (arguments.length < 3) { //逆向找到第一个有效元素当作初始值
var hasV = 0;
for (; i > -1; i--) {
if (i in arr) {
initial = arr[i--];
hasV = 1;
break;
}
}
if (!hasV) {
throw new Error("No component to reduceRight");
}
}
for (; i > -1; i--) {
if (i in arr) {
initial = callback(initial, arr[i], i, arr);
}
}
return initial;
},
/**
* 将一个数组扁平化
* @method expand
* @static
* @param arr {Array} 要扁平化的数组
* @return {Array} 扁平化后的数组
*/
expand: function(arr) {
return [].concat.apply([], arr);
},
/**
* 将一个泛Array转化成一个Array对象。
* @method toArray
* @static
* @param {Array} arr 待处理的Array的泛型对象.
* @return {Array}
*/
toArray: function(arr) {
var ret = [];
for (var i = 0; i < arr.length; i++) {
ret[i] = arr[i];
}
return ret;
},
/**
* 对数组进行包装。
* @method wrap
* @static
* @param {Array} arr 待处理的数组.
* @param {Class} constructor 构造器
* @returns {Object}: 返回new constructor(arr)
*/
wrap: function(arr, constructor) {
return new constructor(arr);
}
};
QW.ArrayH = ArrayH;
}());
function.h.js (针对Function的Helper)
View Code
/**
* @class FunctionH 核心对象Function的扩展
* @singleton
* @namespace QW
* @helper
*/
(function() {
var FunctionH = {
/**
* 函数包装器 methodize,对函数进行methodize化,使其的第一个参数为this,或this[attr]。
* @method methodize
* @static
* @param {function} func要方法化的函数
* @param {string} attr (Optional) 属性
* @return {function} 已方法化的函数
*/
methodize: function(func, attr) {
if (attr) {
return function() {
return func.apply(null, [this[attr]].concat([].slice.call(arguments)));
};
}
return function() {
return func.apply(null, [this].concat([].slice.call(arguments)));
};
},
/** 对函数进行集化,使其第一个参数可以是数组
* @method mul
* @static
* @param {function} func
* @param {bite} opt 操作配置项,缺省表示默认,
1 表示getFirst将只操作第一个元素,
2 表示joinLists,如果第一个参数是数组,将操作的结果扁平化返回
* @return {Object} 已集化的函数
*/
mul: function(func, opt) {
var getFirst = opt == 1,
joinLists = opt == 2;
if (getFirst) {
return function() {
var list = arguments[0];
if (!(list instanceof Array)) {
return func.apply(this, arguments);
}
if (list.length) {
var args = [].slice.call(arguments, 0);
args[0] = list[0];
return func.apply(this, args);
}
};
}
return function() {
var list = arguments[0];
if (list instanceof Array) {
var moreArgs = [].slice.call(arguments, 0),
ret = [],
i = 0,
len = list.length,
r;
for (; i < len; i++) {
moreArgs[0] = list[i];
r = func.apply(this, moreArgs);
if (joinLists) {
if (r) {
ret = ret.concat(r);
}
} else {
ret.push(r);
}
}
return ret;
} else {
return func.apply(this, arguments);
}
};
},
/**
* 函数包装变换
* @method rwrap
* @static
* @param {func}
* @return {Function}
*/
rwrap: function(func, wrapper, idx) {
idx |= 0;
return function() {
var ret = func.apply(this, arguments);
if (idx >= 0) {
ret = arguments[idx];
}
return wrapper ? new wrapper(ret) : ret;
};
},
/**
* 绑定
* @method bind
* @via https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind
* @compatibile ECMA-262, 5th (JavaScript 1.8.5)
* @static
* @param {func} 要绑定的函数
* @obj {object} this_obj
* @param {any} arg1 (Optional) 预先确定的参数
* @param {any} arg2 (Optional) 预先确定的参数
* @return {Function}
*/
bind: function(func, obj) {
var slice = [].slice,
args = slice.call(arguments, 2),
nop = function() {},
bound = function() {
return func.apply(this instanceof nop ? this : (obj || {}), args.concat(slice.call(arguments)));
};
nop.prototype = func.prototype;
bound.prototype = new nop();
return bound;
},
/**
* 懒惰执行某函数:一直到不得不执行的时候才执行。
* @method lazyApply
* @static
* @param {Function} fun 调用函数
* @param {Object} thisObj 相当于apply方法的thisObj参数
* @param {Array} argArray 相当于apply方法的argArray参数
* @param {int} ims interval毫秒数,即window.setInterval的第二个参数.
* @param {Function} checker 定期运行的判断函数。<br/>
对于不同的返回值,得到不同的结果:<br/>
返回true或1,表示需要立即执行<br/>
返回-1,表示成功偷懒,不用再执行<br/>
返回其它值,表示暂时不执行<br/>
* @return {int} 返回interval的timerId
*/
lazyApply: function(fun, thisObj, argArray, ims, checker) {
checker = checker || function() {return true; };
var timer = function() {
var verdict = checker();
if (verdict == 1) {
fun.apply(thisObj, argArray || []);
}
if (verdict == 1 || verdict == -1) {
clearInterval(timerId);
}
},
timerId = setInterval(timer, ims);
return timerId;
}
};
QW.FunctionH = FunctionH;
}());