mass Framework lang模块
是专门针对于数组,类数组,字符串,数字,对象提供了N多便捷方法。正如dom实例是把元素节点包裹到里面进行链式操作一样,dom.lang实例是把上述数据类型包裹起来进行链式操作。但链式操作有一个缺点,就是失去了原来的返回值,因此实例提供了两组方法,一组是用于进行链式操作,此类方法名以“X”结束,除非原始返回值的类型不在数组,数字,字符串,对象这四个范围之内,它总是返回dom.lang实例。另一组则总是返回原始返回值。比如forEach与forEachX是一组。使用方法:dom.lang("aaa").underscored(),dom.lang("bbb").toUpperCase(),dom.lang([1,2,3]).forEach(fn)。此外,它还提供了几个依附于dom命名空间的静态方法。
//========================================= // 语言扩展模块 by 司徒正美 //========================================= (function(global,DOC){ var dom = global[DOC.URL.replace(/(#.+|\W)/g,'')]; var deps = Array.isArray && Object.create ? "" : "ecma"; dom.define("lang", deps, function(){ dom.log("已加载lang模块"); var 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, P = "prototype", H = dom.hasOwnProperty, N = (global.open + '').replace(/open/g, ''); dom.mix(dom,{ //判定是否一个朴素的对象,只能允许是对象对面量及由new Object生成的对象 isPlainObject : function (obj){ return !!obj && dom.type(obj,"Object") && H.call(obj.constructor[P],"isPrototypeOf") ; }, isFunction : function(obj){ return dom.type(obj,"Function") }, isString : function(obj){ return dom.type(obj,"String"); }, isArray: function(obj){ return dom.type(obj,"Array"); }, /** * 是否为原生方法 * @param {Object} obj * @param {Function} method * @return {Boolean} */ isNative : function(obj, method) { var m = obj ? obj[method] : false, r = new RegExp(method, 'g'); return !!(m && typeof m != 'string' && N === (m + '').replace(r, '')); }, globalEval: function( code ) { //IE中,window.eval()和eval()一样只在当前作用域生效。 //Firefox,Safari,Opera中,直接调用eval()为当前作用域,window.eval()调用为全局作用域。 if ( code && /\S/.test(code) ) { var method = global.execScript ? "execScript" : "eval" try{ global[method](code); }catch(e){} } }, parseJSON: function( data ) { if ( typeof data !== "string" || !data ) { return null; } data = data.trim(); if ( global.JSON && global.JSON.parse ) { //使用原生的JSON.parse转换字符串为对象 dom.log("使用原生的JSON.parse转换字符串为对象") return global.JSON.parse( data ); } if ( rvalidchars.test( data.replace( rvalidescape, "@" ) .replace( rvalidtokens, "]" ) .replace( rvalidbraces, "")) ) { //使用new Function生成一个JSON对象 dom.log("使用new Function生成一个JSON对象") return (new Function( "return " + data ))(); } dom.log( "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" ); xml.async = "false"; xml.loadXML( data ); } } catch( e ) { xml = undefined; } if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { dom.log( "Invalid XML: " + data ); } return xml; }, /** * 是否为空对象 * @param {Object} obj * @return {Boolean} */ isEmptyObject: function(obj ) { for ( var name in obj ){ if ( name !== "toJSON" ) { return false; } } return true; }, //包括Array,Arguments,NodeList,HTMLCollection,IXMLDOMNodeList与自定义类数组对象 //select.options集合(它们两个都有item与length属性) isArrayLike : function (obj) { if(!obj || obj.document || obj.nodeType || dom.type(obj,"Function")) return false; return isFinite(obj.length) ; }, //将字符串中的占位符替换为对应的键值 //http://www.cnblogs.com/rubylouvre/archive/2011/05/02/1972176.html format : function(str, object){ var array = dom.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]) return object[name]; return '' ; }); }, /** * 用于拼接多行字符串,免去写<与>与结束标签之苦 * @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) { if (arguments.length <= 1) { stop = start || 0; start = 0; } step = arguments[2] || 1; var len = Math.max(Math.ceil((stop - start) / step), 0); var idx = 0; var range = new Array(len); while(idx < len) { range[idx++] = start; start += step; } return range; }, quote : 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)+ '"'; } })() }, false); if(Array.isArray){ dom.isArray = Array.isArray; } var String2 = dom.String2 = { //判断一个字符串是否包含另一个字符 contains: function(string, separator){ return (separator) ? (separator + this + separator).indexOf(separator + string + separator) > -1 : this.indexOf(string) > -1; }, //以XXX开头 startsWith: function(string, ignorecase) { var start_str = this.substr(0, string.length); return ignorecase ? start_str.toLowerCase() === string.toLowerCase() : start_str === string; }, endsWith: function(string, ignorecase) { var end_str = this.substring(this.length - string.length); return ignorecase ? end_str.toLowerCase() === string.toLowerCase() : end_str === string; }, toArray:function(crash){ return !!crash ? this.split('') : this.split(/\s+/g); }, //得到字节长度 byteLen:function(){ return this.replace(rascii,"--").length; }, empty: function () { return this.valueOf() === ''; }, //判定字符串是否只有空白 blank: function () { return /^\s*$/.test(this); }, //length,新字符串长度,truncation,新字符串的结尾的字段,返回新字符串 truncate :function(length, truncation) { length = length || 30; truncation = truncation === void(0) ? '...' : truncation; return this.length > length ? this.slice(0, length - truncation.length) + truncation :String(this); }, camelize:function(){ return this.replace(/-([a-z])/g, function($1,$2){ return $2.toUpperCase(); }); }, //首字母大写 capitalize: function(){ return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); }, underscored: function() { return this.replace(/([a-z\d])([A-Z]+)/g, '$1_$2').replace(/\-/g, '_').toLowerCase(); }, toInt: function(radix) { return parseInt(this, radix || 10); }, toFloat: function() { return parseFloat(this); }, //http://stevenlevithan.com/regex/xregexp/ escapeRegExp: function(){ return this.replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1'); }, //http://www.cnblogs.com/rubylouvre/archive/2010/02/09/1666165.html //在左边补上一些字符,默认为0 padLeft: function(digits, radix, filling){ var num = this.toString(radix || 10); filling = filling || "0"; while(num.length < digits){ num= filling + num; } return num; }, //在右边补上一些字符,默认为0 padRight: function(digits, radix, filling){ var num = this.toString(radix || 10); filling = filling || "0"; while(num.length < digits){ num += filling; } return num; }, // http://www.cnblogs.com/rubylouvre/archive/2009/11/08/1598383.html times :function(n){ var str = this,res = ""; while (n > 0) { if (n & 1) res += str; str += str; n >>= 1; } return res; } }; var Array2 = dom.Array2 = { //深拷贝当前数组 clone: function(){ var i = this.length, result = []; while (i--) result[i] = cloneOf(this[i]); return result; }, first: function(fn,scope){ if(dom.type(fn,"Function")){ for(var i=0, n = this.length;i < n;i++){ if(fn.call(scope,this[i],i,this)){ return this[i]; } } return null; }else{ return this[0]; } }, last: function(fn, scope) { if(dom.type(fn,"Function")){ for (var i=this.length-1; i > -1; i--) { if (fn.call(scope, this[i], i, this)) { return this[i]; } } return null; }else{ return this[this.length-1]; } }, //判断数组是否包含此元素 contains: function (el) { return this.indexOf(el) !== -1; }, //去掉与传入参数相同的元素 without:function(){ var args = dom.slice(arguments); return this.filter(function (el) { return args.indexOf(el) < 0; }); }, //http://msdn.microsoft.com/zh-cn/library/bb383786.aspx //移除 Array 对象中某个元素的第一个匹配项。 remove: function (item) { var index = this.indexOf(item); if (index !== -1) return Array2.removeAt.call(this,index); return null; }, //移除 Array 对象中指定位置的元素。 removeAt: function (index) { return this.splice(index, 1); }, //对数组进行洗牌,但不影响原对象 // Jonas Raoni Soares Silva http://jsfromhell.com/array/shuffle [v1.0] shuffle: function () { var shuff = (this || []).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 () { return Array2.shuffle.call(this)[0]; }, //取得数字数组中值最小的元素 min: function() { return Math.min.apply(0, this); }, //取得数字数组中值最大的元素 max: function() { return Math.max.apply(0, this); }, //只有原数组不存在才添加它 ensure: function() { var args = dom.slice(arguments); args.forEach(function(el){ if (this.indexOf(el) < 0) this.push(el); },this); return this; }, //取得对象数组的每个元素的特定属性 pluck:function(name){ var result = [],prop; this.forEach(function(el){ prop = el[name]; if(prop != null) result.push(prop); }); return result; }, //根据对象的某个属性进行排序 sortBy: function(fn, scope) { var array = this.map(function(el, index) { return { el: el, re: fn.call(scope, el, index) }; }).sort(function(left, right) { var a = left.re, b = right.re; return a < b ? -1 : a > b ? 1 : 0; }); return Array2.pluck.call(array,'el'); }, // 以数组形式返回原数组中不为null与undefined的元素 compact: function () { return this.filter(function (el) { return el != null; }); }, // 返回没有重复值的新数组 unique: function () { var result = []; for(var i=0,l=this.length; i < l; i++) { if(result.indexOf(this[i]) < 0){ result.push(this[i]); } } return result; }, //对数组进行平坦化处理,返回一个一维数组 flatten: function() { var result = [],self = Array2.flatten; this.forEach(function(value) { if (dom.isArray(value)) { result = result.concat(self.call(value)); } else { result.push(value); } }); return result; }, //returns a new Array with the elements that are in a but not in b diff : function(array) { var result = this.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; } } var Number2 = dom.Number2 ={ times: function(fn, bind) { for (var i=0; i < this; i++) fn.call(bind, i); return this; }, padLeft:function(digits, radix, filling){ return String2.padLeft.apply(this,[digits, radix, filling]); }, padRight:function(digits, radix, filling){ return String2.padRight.apply(this,[digits, radix, filling]); }, //确保数值在[n1,n2]闭区间之内,如果超出限界,则置换为离它最近的最大值或最小值 constrain:function(n1,n2){ var a = [n1,n2].sort(),num = Number(this); if(num < a[0]) num = a[0]; if(num > a[1]) num = a[1]; return num; }, //求出距离原数最近的那个数 nearer:function(n1,n2){ var num = Number(this), diff1 = Math.abs(num - n1), diff2 = Math.abs(num - n2); return diff1 < diff2 ? n1 : n2 }, upto: function(number, fn, scope) { for (var i=this+0; i <= number; i++) fn.call(scope, i); return this; }, downto: function(number, fn, scope) { for (var i=this+0; i >= number; i--) fn.call(scope, i); return this; }, round: function(base) { if (base) { base = Math.pow(10, base); return Math.round(this * base) / base; } else { return Math.round(this); } } } var mathFns = ["abs", "acos", "asin", "atan", "atan2", "ceil", "cos", "exp", "floor", "log", "pow","sin", "sqrt", "tan"]; mathFns.forEach(function(name){ Number2[name] = function(){ return Math[name](this); } }); function cloneOf(item){ switch(dom.type(item)){ case "Array": return Array2.clone.call(item); case "Object": return Object2.clone.call(item); default: return item; } } //使用深拷贝方法将多个对象或数组合并成一个 function mergeOne(source, key, current){ if(source[key] && typeof source[key] == "object"){ Object2.merge.call(source[key], current); }else{ source[key] = cloneOf(current) } return source; }; var Object2 = dom.Object2 = { //根据传入数组取当前对象相关的键值对组成一个新对象返回 subset: function(keys){ var results = {}; for (var i = 0, l = keys.length; i < l; i++){ var k = keys[i]; results[k] = this[k]; } return results; }, //遍历对象的键值对 forEach: function(fn,scope){ for(var name in this){ fn.call(scope,this[name],name,this); } if(dom.DONT_ENUM){ for(var i = 0; name = dom.DONT_ENUM[i++]; ){ H.call(this,name) && fn.call(scope,this[name],name,this); } } }, //进行深拷贝,返回一个新对象,如果是拷贝请使用dom.mix clone: function(){ var clone = {}; for (var key in this) clone[key] = cloneOf(this[key]); return clone; }, merge: function(k, v){ var target = this,obj,key; //为目标对象添加一个键值对 if (typeof k === "string") return mergeOne(target, k, v); //合并多个对象 for (var i = 0, l = arguments.length; i < l; i++){ obj = arguments[i]; for ( key in obj){ mergeOne(target, key, obj[key]); } } return target; }, //去掉与传入参数相同的元素 without: function() { var args = dom.slice(arguments),result = {}, key; for (key in this) { if (args.indexOf(key) < 0) { result[key] = this[key]; } } return result; } } var inner = { String : ["charAt", "charCodeAt", "concat", "indexOf", "lastIndexOf", "localeCompare", "match", "replace","search", "slice", "split", "substring", "toLowerCase", "toLocaleLowerCase", "toUpperCase", "toLocaleUpperCase", "trim", "toJSON"], Array : [ "toLocaleString","concat", "join", "pop", "push", "shift", "slice", "sort", "reverse","splice", "unshift", "indexOf", "lastIndexOf", "every", "some", "forEach", "map","filter", "reduce", "reduceRight"], Number : ["toLocaleString", "toFixed", "toExponential", "toPrecision", "toJSON"], Object : ["toLocaleString", "hasOwnerProperty", "isPrototypeOf", "propertyIsEnumerable" ] } var adjustOne = dom.oneObject(["String","Array","Number","Object"]); var Lang = dom.lang = function(obj){ var type = dom.type(obj), that = this; if(type == "NodeList" || type === "Arguments" || type === "Object" && isFinite(obj.length)){ obj = dom.slice(obj); type = "Array"; } if(adjustOne[type]){ if(!(that instanceof Lang)){ that = new Lang; } that.target = obj; that.type = type; return that; }else{// undefined boolean null return obj } } var proto = Lang[P] = { constructor:Lang, valueOf:function(){ return this.target; }, toString:function(){ return this.target + ""; } }; function force(type){ var methods = inner[type].concat(Object.keys(dom[type+2])); methods.forEach(function(name){ proto[name] = function(){ var obj = this.target; var method = obj[name] ? obj[name] : dom[this.type+2][name]; var result = method.apply(obj,arguments); return result; } proto[name+"X"] = function(){ var obj = this.target; var method = obj[name] ? obj[name] : dom[this.type+2][name]; var result = method.apply(obj,arguments); return Lang.call(this,result) ; } }); return force; }; force("Array")("String")("Number")("Object"); }); })(this,this.document); //2011.7.12 //将toArray转移到lang模块下 //2011.7.26 //去掉toArray方法,添加globalEval parseJSON parseXML方法 //2011.8.6 //增加tag方法 //2011.8.14 //更新隐藏的命名空间,更新range方法
机器瞎学/数据掩埋/模式混淆/人工智障/深度遗忘/神经掉线/计算机幻觉/专注单身二十五年