mass Framework lang模块 v4
本次升级引进一些非常有用的方法,去掉一些用户也能简单实现的方法。详细如下:
- 字符串的blank, empty, toInt, toFloat方法, 它们被移到more/string模块中去。
- Object.forEach方法去掉,取而代之是Object.each,数组也增加一个叫each方法。each方法不同于forEach,它可以通过回调返回false中断迭代。
- 添加$.throttle与$.debounce,用于处理函数的调用频率。
- 精简一下$.dump的方法代码量。
- 添加stripTags,stripScripts,escapeHTML,unescapeHTML这四个在Prototype.js就赫赫有名的方法,专门用于处理用户输入输出。
- padRight与padLeft在实现就是一行的差异,现在padRight是在内部调用padLeft实现。
- 添加wbr字符串方法,对长字符进行换行,比如英文,数字在中文语句中不会断开,里面插入<wbr>就可以了。
地址:https://github.com/RubyLouvre/mass-Framework/blob/master/src/lang.js
//=========================================
// 类型扩展模块v3 by 司徒正美
//=========================================
$.define("lang", Array.isArray ? "" : "lang_fix",function(){
// $.log("已加载语言扩展模块");
var global = this, rascii = /[^\x00-\xff]/g,
rformat = /\\?\#{([^{}]+)\}/gm,
rnoclose = /^(area|base|basefont|bgsound|br|col|frame|hr|img|input|isindex|link|meta|param|embed|wbr)$/i,
// JSON RegExp
rvalidchars = /^[\],:{}\s]*$/,
rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
str_eval = global.execScript ? "execScript" : "eval",
str_body = (global.open + '').replace(/open/g, '');
$.mix({
//判定是否是一个朴素的javascript对象(Object或JSON),不是DOM对象,不是BOM对象,不是自定义类的实例。
isPlainObject: function (obj){
if(!$.type(obj,"Object") || $.isNative(obj, "reload") ){
return false;
}
try{//不存在hasOwnProperty方法的对象肯定是IE的BOM对象或DOM对象
for(var key in obj)//只有一个方法是来自其原型立即返回flase
if(!({}).hasOwnProperty.call(obj, key)){//不能用obj.hasOwnProperty自己查自己
return false
}
}catch(e){
return false;
}
return true;
},
//判定method是否为obj的原生方法,如$.isNative(global,"JSON")
isNative: function(obj, method) {
var m = obj ? obj[method] : false, r = new RegExp(method, 'g');
return !!(m && typeof m != 'string' && str_body === (m + '').replace(r, ''));
},
/**
* 是否为空对象
* @param {Object} obj
* @return {Boolean}
*/
isEmptyObject: function(obj ) {
for ( var i in obj ){
return false;
}
return true;
},
//限定为Array, Arguments, NodeList与拥有非负整数的length属性的Object对象,视情况添加字符串
isArrayLike: function (obj, str) {//是否包含字符串
var type = $.type(obj);
if(type === "Array" || type === "NodeList" || type === "Arguments" || str && type === "String"){
return true;
}
if( type === "Object" ){
var i = obj.length;
return i >= 0 && parseInt( i ) === i;//非负整数
}
return false;
},
makeArray: function(obj){
if (obj == null) {
return [];
}
if($.isArrayLike(obj)){
return $.slice( obj )
}
return [ obj ]
},
//将字符串中的占位符替换为对应的键值
//http://www.cnblogs.com/rubylouvre/archive/2011/05/02/1972176.html
format: function(str, object){
var array = $.slice(arguments,1);
return str.replace(rformat, function(match, name){
if (match.charAt(0) == '\\')
return match.slice(1);
var index = Number(name)
if(index >=0 )
return array[index];
if(object && object[name] !== void 0)
return object[name];
return '' ;
});
},
/**
* 用于拼接多行HTML片断,免去写<与>与结束标签之苦
* @param {String} tag 可带属性的开始标签
* @param {String} innerHTML 可选
* @param {Boolean} xml 可选 默认false,使用HTML模式,需要处理空标签
* @example var html = T("P title=aaa",T("span","111111")("strong","22222"))("div",T("div",T("span","两层")))("H1",T("span","33333"))('',"这是纯文本");
* console.log(html+"");
* @return {Function}
*/
tag: function (start, content, xml){
xml = !!xml
var chain = function(start, content, xml){
var html = arguments.callee.html;
start && html.push("<",start,">");
content = ''+(content||'');
content && html.push(content);
var end = start.split(' ')[0];//取得结束标签
if(end && (xml || !rnoclose.test(end))){
html.push("</",end,">");
}
return chain;
}
chain.html = [];
chain.toString = function(){
return this.html.join("");
}
return chain(start,content,xml);
},
// Generate an integer Array containing an arithmetic progression. A port of
// the native Python `range()` function. See
// [the Python documentation](http://docs.python.org/library/functions.html#range).
range: function(start, stop, step) {
step || (step = 1);
if (arguments.length < 2) {
stop = start || 0;
start = 0;
}
var index = -1,
length = Math.max(Math.ceil((stop - start) / step), 0),
result = Array(length);
while (++index < length) {
result[index] = start;
start += step;
}
return result;
},
// 为字符串两端添上双引号,并对内部需要转义的地方进行转义
quote: global.JSON && JSON.stringify || String.quote || (function(){
var meta = {
'\t':'t',
'\n':'n',
'\v':'v',
'\f':'f',
'\r':'r',
'\'':'\'',
'\"':'\"',
'\\':'\\'
},
reg = /[\x00-\x1F\'\"\\\u007F-\uFFFF]/g,
regFn = function(c){
if (c in meta) {
return '\\' + meta[c];
}
var ord = c.charCodeAt(0);
return ord < 0x20 ? '\\x0' + ord.toString(16)
: ord < 0x7F ? '\\' + c
: ord < 0x100 ? '\\x' + ord.toString(16)
: ord < 0x1000 ? '\\u0' + ord.toString(16)
: '\\u' + ord.toString(16)
};
return function (str) {
return '"' + str.replace(reg, regFn)+ '"';
}
})(),
dump: function(obj, indent) {
indent = indent || "";
if (obj == null)//处理null,undefined
return indent + "obj";
if (obj.nodeType === 9)
return indent + "[object Document]";
if (obj.nodeType)
return indent + "[object " + (obj.tagName || "Node") +"]";
var arr = [], type = $.type(obj),self = $.dump ,next = indent + "\t";
switch (type) {
case "Boolean":
case "Number":
case "NaN":
case "RegExp":
return indent + obj;
case "String":
return indent + $.quote(obj);
case "Function":
return (indent + obj).replace(/\n/g, "\n" + indent);
case "Date":
return indent + '(new Date(' + obj.valueOf() + '))';
case "Window" :
return indent + "[object "+type +"]";
default:
if($.isArrayLike(obj)){
for (var i = 0, n = obj.length; i < n; ++i)
arr.push(self(obj[i], next).replace(/^\s* /g, next));
return indent + "[\n" + arr.join(",\n") + "\n" + indent + "]";
}
if($.isPlainObject(obj)){
for ( i in obj) {
arr.push(next + self(i) + ": " + self(obj[i], next).replace(/^\s+/g, ""));
}
return indent + "{\n" + arr.join(",\n") + "\n" + indent + "}";
}
return indent + "[object "+type +"]";
}
},
//http://www.schillmania.com/content/projects/javascript-animation-1/
//http://www.cnblogs.com/rubylouvre/archive/2010/04/09/1708419.html
parseJS: function( code ) {
//IE中,global.eval()和eval()一样只在当前作用域生效。
//Firefox,Safari,Opera中,直接调用eval()为当前作用域,global.eval()调用为全局作用域。
if ( code && /\S/.test(code) ) {
try{
global[str_eval](code);
}catch(e){ }
}
},
parseJSON: function( data ) {
if ( typeof data !== "string" || !data ) {
return null;
}
data = data.trim();
if ( global.JSON && global.JSON.parse ) {
//使用原生的JSON.parse转换字符串为对象
return global.JSON.parse( data );
}
if ( rvalidchars.test( data.replace( rvalidescape, "@" )
.replace( rvalidtokens, "]" )
.replace( rvalidbraces, "")) ) {
//使用new Function生成一个JSON对象
return (new Function( "return " + data ))();
}
throw "Invalid JSON: " + data ;
},
// Cross-browser xml parsing
parseXML: function ( data,xml,tmp ) {
try {
if ( global.DOMParser ) { // Standard
tmp = new DOMParser();
xml = tmp.parseFromString(data , "text/xml" );
} else { // IE
xml = new ActiveXObject("Microsoft.XMLDOM" );//"Microsoft.XMLDOM"
xml.async = "false";
xml.loadXML( data );
}
} catch( e ) {
xml = undefined;
}
if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
throw "Invalid XML: " + data ;
}
return xml;
},
//http://oldenburgs.org/playground/autocomplete/
//http://benalman.com/projects/jquery-throttle-debounce-plugin/
//http://www.cnblogs.com/ambar/archive/2011/10/08/throttle-and-debounce.html
throttle: function( delay, no_trailing, callback, debounce_mode ) {
var timeout_id, last_exec = 0;//ms 时间内只执行 fn 一次, 即使这段时间内 fn 被调用多次
if ( typeof no_trailing !== 'boolean' ) {
debounce_mode = callback;
callback = no_trailing;
no_trailing = undefined;
}
function wrapper() {
var that = this,
elapsed = +new Date() - last_exec,
args = arguments;
function exec() {
last_exec = +new Date();
callback.apply( that, args );
};
function clear() {
timeout_id = undefined;
};
if ( debounce_mode && !timeout_id ) {
exec();
}
timeout_id && clearTimeout( timeout_id );
if ( debounce_mode === undefined && elapsed > delay ) {
exec();
} else if ( no_trailing !== true ) {
timeout_id = setTimeout( debounce_mode ? clear : exec, debounce_mode === undefined ? delay - elapsed : delay );
}
};
wrapper.uniqueNumber = $.getUid(callback)
return wrapper;
},
debounce : function( delay, at_begin, callback ) {
return callback === undefined
? $.throttle( delay, at_begin, false )
: $.throttle( delay, callback, at_begin !== false );
}
}, false);
"Array,Function".replace($.rword, function( method ){
$[ "is"+method ] = function(obj){
return obj && ({}).toString.call(obj) === "[object "+method+"]";
}
});
"each,map".replace($.rword, function( method ){
$[ method ] = function(obj, fn, scope){
return $[ $.isArrayLike(obj,true) ? "Array" : "Object" ][ method ](obj, fn, scope);
}
});
if(Array.isArray){
$.isArray = Array.isArray;
}
//这只是一个入口
$.lang = function(obj, type){
return adjust(new Chain, obj, type)
}
//调整Chain实例的重要属性
function adjust(chain, obj, type){
type = type || $.type(obj);
if( type != "Array" && $.isArrayLike(type) ){
obj = $.slice(obj);
type = "Array";
}
chain.target = obj;
chain.type = type;
return chain
}
//语言链对象
var Chain = function(){ }
Chain.prototype = {
constructor: Chain,
toString: function(){
return this.target + "";
},
value: function(){
return this.target;
}
};
var retouch = function(method){//函数变换,静态转原型
return function(){
[].unshift.call(arguments,this)
return method.apply(null,arguments)
}
}
var proto = Chain.prototype;
//构建语言链对象的四个重要工具:$.String, $.Array, $.Number, $.Object
"String,Array,Number,Object".replace($.rword, function(Type){
$[ Type ] = function(ext){
var isNative = typeof ext == "string",
methods = isNative ? ext.match($.rword) : Object.keys(ext);
methods.forEach(function(name){
$[ Type ][name] = isNative ? function(obj){
return obj[name].apply(obj,$.slice(arguments,1) );
} : ext[name];
proto[name] = function(){
var target = this.target;
if( target == null){
return this;
}else{
if( !(target[name] || $[ this.type ][name]) ){
throw "$."+ this.type + "."+name+" does not exist!"
}
var method = isNative ? target[name] : retouch( $[ this.type ][name] ),
next = this.target = method.apply( target, arguments ),
type = $.type( next );
if( type === this.type){
return this;
}else{
return adjust(this, next, type)
}
}
}
});
}
});
$.String({
//判断一个字符串是否包含另一个字符
contains: function(target, str, separator){
return (separator) ? !!~(separator + target + separator).indexOf(separator + str + separator) : !!~target.indexOf(str);
},
//判定是否以给定字符串开头
startsWith: function(target, str, ignorecase) {
var start_str = target.substr(0, str.length);
return ignorecase ? start_str.toLowerCase() === str.toLowerCase() :
start_str === str;
},
//判定是否以给定字符串结尾
endsWith: function(target, str, ignorecase) {
var end_str = target.substring(target.length - str.length);
return ignorecase ? end_str.toLowerCase() === str.toLowerCase() :
end_str === str;
},
//得到字节长度
byteLen: function(target){
return target.replace(rascii,"--").length;
},
//length,新字符串长度,truncation,新字符串的结尾的字段,返回新字符串
truncate: function(target, length, truncation) {
length = length || 30;
truncation = truncation === void(0) ? '...' : truncation;
return target.length > length ?
target.slice(0, length - truncation.length) + truncation : String(target);
},
//转换为驼峰风格
camelize: function(target){
if (target.indexOf('-') < 0 && target.indexOf('_') < 0) {
return target;//提前判断,提高getStyle等的效率
}
return target.replace(/[-_][^-_]/g, function (match) {
return match.charAt(1).toUpperCase();
});
},
//转换为连字符风格
underscored: function(target) {
return target.replace(/([a-z\d])([A-Z]+)/g, '$1_$2').replace(/\-/g, '_').toLowerCase();
},
//首字母大写
capitalize: function(target){
return target.charAt(0).toUpperCase() + target.substring(1).toLowerCase();
},
//去掉字符串中的html标签,但这方法有缺陷,如里面有script标签,会把这些不该显示出来的脚本也显示出来了
stripTags: function (target) {
return String(target ||"").replace(/<[^>]+>/g, '');
},
//移除字符串中所有的 HTML script 块。弥补stripTags方法对script标签的缺陷
stripScripts: function(target){
return String(target ||"").replace(/<script[^>]*>([\S\s]*?)<\/script>/img,'')
},
//将字符串中的html代码转换为可以直接显示的格式,
escapeHTML: function (target) {
return target.replace(/&/g,'&')
.replace(/</g,'<')
.replace(/>/g,'>')
.replace(/"/g, """)
.replace(/'/g, "'");
},
//还原为可被文档解析的HTML标签
unescapeHTML: function (target) {
return target.replace(/"/g,'"')
.replace(/</g,'<')
.replace(/>/g,'>')
.replace(/&/g, "&");
//处理转义的中文和实体字符
return str.replace(/([\d]+);/g, function(_0, _1){
return String.fromCharCode(parseInt(_1, 10));
});
},
/**
为目标字符串添加wbr软换行
1.支持html标签、属性以及字符实体。<br>
2.任意字符中间都会插入wbr标签,对于过长的文本,会造成dom节点元素增多,占用浏览器资源。
3.在opera下,浏览器默认css不会为wbr加上样式,导致没有换行效果,可以在css中加上 wbr:after { content: "\00200B" } 解决此问题*/
wbr: function (target) {
return String(target)
.replace(/(?:<[^>]+>)|(?:?[0-9a-z]{2,6};)|(.{1})/gi, '$&<wbr>')
.replace(/><wbr>/g, '>');
},
//http://stevenlevithan.com/regex/xregexp/
//将字符串安全格式化为正则表达式的源码
escapeRegExp: function( target ){
return target.replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1');
},
//http://www.cnblogs.com/rubylouvre/archive/2010/02/09/1666165.html
//在左边补上一些字符,默认为0
padLeft: function( target, digits, filling, radix , right){
var num = target.toString(radix || 10);
filling = filling || "0";
while(num.length < digits){
if(!right){
num = filling + num;
}else{
num += filling;
}
}
return num;
},
//在右边补上一些字符,默认为0
padRight: function(target, digits, filling, radix){
return $.String.padLeft(target, digits, filling, radix, true)
}
});
$.String("charAt,charCodeAt,concat,indexOf,lastIndexOf,localeCompare,match,"+
"replace,search,slice,split,substring,toLowerCase,toLocaleLowerCase,toUpperCase,trim,toJSON")
$.Array({
//深拷贝当前数组
clone: function( target ){
var i = target.length, result = [];
while (i--) result[i] = cloneOf(target[i]);
return result;
},
each: function( target, fn, scope ){
for(var i = 0, n = target.length; i < n; i++){
if (fn.call(scope || target[i], target[i], i, target) === false)
break;
}
return target;
},
//取得第一个元素或对它进行操作
first: function( target, fn, scope ){
if($.type(fn,"Function")){
for(var i=0, n = target.length; i < n; i++){
if(fn.call( scope,target[i], i, target )){
return target[i];
}
}
return null;
}else{
return target[0];
}
},
//取得最后一个元素或对它进行操作
last: function( target, fn, scope ) {
if($.type(fn,"Function")){
for (var i=target.length-1; i > -1; i--) {
if (fn.call(scope, target[i], i, target)) {
return target[i];
}
}
return null;
}else{
return target[target.length-1];
}
},
//判断数组是否包含此元素
contains: function ( target, item ) {
return !!~target.indexOf(item) ;
},
//http://msdn.microsoft.com/zh-cn/library/bb383786.aspx
//移除 Array 对象中某个元素的第一个匹配项。
remove: function ( target, item ) {
var index = target.indexOf(item);
if (~index ) return $.Array.removeAt(target, index);
return null;
},
//移除 Array 对象中指定位置的元素。
removeAt: function ( target, index ) {
return target.splice(index, 1);
},
//对数组进行洗牌,但不影响原对象
// Jonas Raoni Soares Silva http://jsfromhell.com/array/shuffle [v1.0]
shuffle: function ( target ) {
var shuff = target.concat(), j, x, i = shuff.length;
for (; i > 0; j = parseInt(Math.random() * i), x = shuff[--i], shuff[i] = shuff[j], shuff[j] = x) {};
return shuff;
},
//从数组中随机抽选一个元素出来
random: function ( target ) {
return $.Array.shuffle( target )[0];
},
//取得数字数组中值最小的元素
min: function( target ) {
return Math.min.apply(0, target);
},
//取得数字数组中值最大的元素
max: function( target ) {
return Math.max.apply(0, target);
},
//取得对象数组的每个元素的特定属性
pluck: function( target, name ){
var result = [], prop;
target.forEach(function(item){
prop = item[name];
if(prop != null)
result.push(prop);
});
return result;
},
//根据对象的某个属性进行排序
sortBy: function( target, fn, scope ) {
var array = target.map(function(item, index) {
return {
el: item,
re: fn.call(scope, item, index)
};
}).sort(function(left, right) {
var a = left.re, b = right.re;
return a < b ? -1 : a > b ? 1 : 0;
});
return $.Array.pluck(array,'el');
},
// 以数组形式返回原数组中不为null与undefined的元素
compact: function ( target ) {
return target.filter(function (el) {
return el != null;
});
},
//取差集(补集)
diff: function( target, array ) {
var result = target.slice();
for ( var i = 0; i < result.length; i++ ) {
for ( var j = 0; j < array.length; j++ ) {
if ( result[i] === array[j] ) {
result.splice(i, 1);
i--;
break;
}
}
}
return result;
},
merge: function( target, array ){
var i = target.length, j = 0;
for ( var n = array.length; j < n; j++ ) {
target[ i++ ] = array[ j ];
}
target.length = i;
return target;
},
//取并集
union: function( target, array ){
$.Array.merge(target, array)
return $.Array.unique( target );
},
//取交集
intersect: function( target, array ){
return target.filter(function(n) {
return ~array.indexOf(n);
});
},
// 返回没有重复值的新数组
unique: function ( target ) {
var result = [];
o:for(var i = 0, n = target.length; i < n; i++) {
for(var x = i + 1 ; x < n; x++) {
if(target[x] === target[i])
continue o;
}
result.push(target[i]);
}
return result;
},
//对数组进行平坦化处理,返回一个一维数组
flatten: function(target) {
var result = [],self = $.Array.flatten;
target.forEach(function(item) {
if ($.isArray(item)) {
result = result.concat(self(item));
} else {
result.push(item);
}
});
return result;
}
});
$.Array("concat,join,pop,push,shift,slice,sort,reverse,splice,unshift"+
"indexOf,lastIndexOf,every,some,forEach,map,filter,reduce,reduceRight")
var NumberExt = {
times: function(target, fn, bind) {
for (var i=0; i < target; i++)
fn.call(bind, i);
return target;
},
//确保数值在[n1,n2]闭区间之内,如果超出限界,则置换为离它最近的最大值或最小值
constrain: function(target, n1, n2){
var a = [n1, n2].sort();
if(target < a[0]) target = a[0];
if(target > a[1]) target = a[1];
return target;
},
upto: function(target, number, fn, scope) {
for (var i=target+0; i <= number; i++)
fn.call(scope, i);
return target;
},
downto: function(target, number, fn, scope) {
for (var i=target+0; i >= number; i--)
fn.call(scope, i);
return target;
},
//求出距离原数最近的那个数
nearer: function(target, n1, n2){
var diff1 = Math.abs(target - n1),
diff2 = Math.abs(target - n2);
return diff1 < diff2 ? n1 : n2
},
round: function(target, base) {
if (base) {
base = Math.pow(10, base);
return Math.round(target * base) / base;
} else {
return Math.round(target);
}
}
}
"padLeft,padRight".replace($.rword, function(name){
NumberExt[name] = $.String[name];
});
"abs,acos,asin,atan,atan2,ceil,cos,exp,floor,log,pow,sin,sqrt,tan".replace($.rword,function(name){
NumberExt[name] = Math[name];
});
$.Number(NumberExt);
$.Number("toFixed,toExponential,toPrecision,toJSON")
function cloneOf(item){
var name = $.type(item);
switch(name){
case "Array":
case "Object":
return $[name].clone(item);
default:
return item;
}
}
//使用深拷贝方法将多个对象或数组合并成一个
function mergeOne(source, key, current){
if( $.isPlainObject(source[key]) ){//只处理纯JS对象,不处理window与节点
$.Object.merge(source[key], current);
}else {
source[key] = cloneOf(current)
}
return source;
};
$.Object({
//根据传入数组取当前对象相关的键值对组成一个新对象返回
subset: function(target, props){
var result = {};
props.forEach(function(prop){
result[prop] = target[prop];
});
return result;
},
//遍历对象的键值对
each: function(target, fn, scope){
var keys = Object.keys(target);
for(var i = 0, n = keys.length; i < n; i++){
var key = keys[i], value = target[key];
if (fn.call(scope || value, value, key, target) === false)
break;
}
return target;
},
map: function(target, fn, scope){
return Object.keys(target).map(function(name){
return fn.call(scope, target[name], name, target);
}, target);
},
//进行深拷贝,返回一个新对象,如果是拷贝请使用$.mix
clone: function(target){
var clone = {};
for (var key in target) {
clone[key] = cloneOf(target[key]);
}
return clone;
},
merge: function(target, k, v){
var obj, key;
//为目标对象添加一个键值对
if (typeof k === "string")
return mergeOne(target, k, v);
//合并多个对象
for (var i = 1, n = arguments.length; i < n; i++){
obj = arguments[i];
for ( key in obj){
if(obj[key] !== void 0){
mergeOne(target, key, obj[key]);
}
}
}
return target;
},
//去掉与传入参数相同的元素
without: function(target, array) {
var result = {}, key;
for (key in target) {//相当于构建一个新对象,把不位于传入数组中的元素赋给它
if (!~array.indexOf(key) ) {
result[key] = target[key];
}
}
return result;
}
});
$.Object("hasOwnerProperty,isPrototypeOf,propertyIsEnumerable");
return $.lang;
});
机器瞎学/数据掩埋/模式混淆/人工智障/深度遗忘/神经掉线/计算机幻觉/专注单身二十五年
浙公网安备 33010602011771号