必须事先声明,本人不赞成入侵 js 对象原型的做法。但是之所以要这样,是出于使用频率上的考虑。若不是这几个方法调用的频繁,决不会贸然加入原型里面去。
String.prototype.format
定义带标记的字符串,并用传入的字符替换标记。每个标记必须是唯一的,而且必须要像{0},{1}...{n}这样地自增长。例如:
var cls = 'my-class', text = 'Some text'; var s = String.format('<div class="{0}">{1}</div>', cls, text); //s现在是字符串:s now contains the string: '<div class="my-class">Some text</div>'
String.prototype.format 源码如下(该方法应用了“函数自覆盖模式”,参见我以往文章《函数自覆盖模式》介绍):
/** * 格式化字符串。 * @param {String} string 带标记的字符串,或者可变长度的字符串参数。 * @param {String} value1 第一个值,替换{0}。The value to replace token {0} * @param {String} value2 第二个值,替换{1}...等等(可以有任意多个)。Etc... * @return {String} 转化过的字符串。The formatted string */ String.prototype.format = function () { var regexp = /{(\d+)}/g, replace = String.prototype.replace; function replaceEl(m, i) { return this[i]; // this为arguments } /* At first run, with override it. */ var fn = String.prototype.format = function () { replaceEl.scope = arguments; // 委托作用域 return replace.call(this, regexp, replaceEl.delegate()); } return fn.apply(this, arguments); // first run }
Date.prototype.format
日期格式化。详见我以往博客文章:《JavaScript自定义日期格式化函数》http://blog.csdn.net/zhangxin09/archive/2011/01/01/6111294.aspx 例子:
alert(new Date().format("yyyy-MM-dd hh:mm:ss"));
Date.prototype.format 源码如下:
/** * 日期格式化 * @param {String} format * @return {String} */ Date.prototype.format = function (format) { var $1, o = { "M+": this.getMonth() + 1, // 月份,从0开始算 "d+": this.getDate(), // 日期 "h+": this.getHours(), // 小时 "m+": this.getMinutes(), // 分钟 "s+": this.getSeconds(), // 秒钟 // 季度 quarter "q+": Math.floor((this.getMonth() + 3) / 3), "S": this.getMilliseconds() // 千秒 }; var key, value; if (/(y+)/.test(format)) { $1 = RegExp.$1, format = format.replace($1, String(this.getFullYear()).substr(4 - $1)); } for (key in o) { // 如果没有指定该参数,则子字符串将延续到 stringvar 的最后。 if (new RegExp("(" + key + ")").test(format)) { $1 = RegExp.$1, value = String(o[key]), value = $1.length == 1 ? value : ("00" + value).substr(value.length), format = format.replace($1, value); } } return format; }
Function.prototype.delegate
delegate() 即是委派的意思,Function.prototype.delegate() 就是函数的委托。delegate 方法字在我所使用的库中应用广泛,大体可以分为两个地方的使用,即在函数的参数中使用和在函数的作用域中使用。后者指的是封装对象(this或者环绕闭包)。delegate 方法可以使得函数的 this 指针改变。预设函数的作用域。考查下面两个方法:
Function.prototype.delegateScope = function (scope){ var self = this; return function(){ return self.apply(scope, arguments); } } Function.prototype.delegateArgs = function(){ var self = this, args = arguments; return function(){ return self.apply(this, args); }; }
Function.prototype.delegate 源码如下(另有 after 方法,比较简单,请看源码):
/** * 函数委托 force Args! so there's no args, it server as Args! * @return {Function} */ Function.prototype.delegate = function () { var self = this, scope = this.scope, args = arguments, aLength = arguments.length, fnToken = 'function'; return function () { var bLength = arguments.length , Length = (aLength > bLength) ? aLength : bLength; // mission one: for (var i = 0; i < Length; i++) { if (arguments[i]) { args[i] = arguments[i]; // 拷贝参数 } } args.length = Length; // 在 MS jscript下面,arguments作为数字来使用还是有问题,就是length不能自动更新。修正如左: // mission two: for (var i = 0, j = args.length; i < j; i++) { var _arg = args[i]; if (_arg && typeof _arg == fnToken && _arg.late == true) { args[i] = _arg.apply(scope || this, args); } } return self.apply(scope || this, args); }; } if (!Function.prototype.bind) { Function.prototype.bind = function (scope) { this.scope = scope; return this.delegate(); } } /** * 设置一个后置函数。 * @param {Function} composeFn * @param {Boolean} isForceCall 是否强行执行 call 方法。设置为 true 在数组作为单独对象的时候有用。 * @return {Function} */ Function.prototype.after = function (composeFn, isForceCall, scope) { var self = this; return function () { var result = self.apply(scope || this, arguments); if (isForceCall) { return composeFn.call(this, result); } return result && (typeof result.pop != 'undefined') && (typeof result.pop != 'unknown') ? composeFn.apply(this, result) : composeFn.call(this, result); }; }
碉堡了!
有次使用 String.prototype.format,发现它要依赖 Function.prototype.delegate,而且又闭包、又正则什么乱七八糟的,十分累的说。于是上网搜索更好的方案,起初是抱着试试看的心态,没想发现一个极其简洁的思路!十分自然而且效率高。回想之前搞的,可能也是从这么简单开始的,但越走越后,却走火入魔了,到现在真是“反人类的”。
String.prototype.format = function () { var str = this; for(var i = 0, j = arguments.length; i < j; i++){ str = str.replace(new RegExp('\\{' + i +'\\}', 'g'), arguments[i]); } return str; } console.log('hihih {0}, ,{2}'.format('dfasda', '34324343','dffds34324'));