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)
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, "&quot;").replace(/'/g, "&#039;");
},

/**
* 与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;

}());


posted on 2011-03-21 19:09  JKisJK  阅读(...)  评论(...编辑  收藏

导航