奇淫技巧和西天取经
题目:用 JavaScript 代码实现空位补零,比如 pad(12, 3) => 012
实现一:
/* 平淡无奇法 */
function pad(num, n) {
var i = (num + "").length;
while(i++ < n) num = "0" + num;
return num;
}
上面的代码太平淡无奇,体现不了我的真实水平。于是有了实现二:
/* 神奇递归法 */
function pad2(num, n) {
if ((num + "").length >= n) return num;
return pad2("0" + num, n);
}
神奇的递归,每次都能让 mm 投来赞美和钦慕的眼神~~
然而,高手过招,讲究的是一招致命。上面的代码居然用了两行,简直是侮辱。琢磨一下,一行神奇的代码涌上心头:
/* 奇淫技巧法 */
function pad3(num, n) {
return (Array(n).join(0) + num).slice(-n);
}
这次 mm 投来的是膜拜的眼神了,hiahia~~~
=== 我不是空间分隔线,我是很长很长的时间分割线。经历了 n 年后 ===
一日,秋高气爽,心旷神怡。与友闲坐菩提树下,把酒下棋。
友曰:BP 君,自从你走后,可害苦了我。你留下的那些神奇代码,害我头发提前掉了 3 年。
我大惊:此话怎讲?
友一脸不堪回首:记得那个神奇的 pad3 函数不?在你走后 1 年内,公司的业务激增。pad3 有个 bug, 某些情况下会截取掉数字的前几位。比如 pad3(123456, 5), 返回的是 23456. 这 bug 被黑客发现了,导致了好几起大规模的钓鱼事件,公司损失上百万。当时老总勒令我一天内找出 bug 所在,老兄你的神奇代码却害得我花了 3 天才定位到。除了 pad3, 还有一个神奇的 xxoo9 函数,当时……
老友还在絮絮叨叨,我听完第一段时,已黯然失魂。低头琢磨 pad3 的写法,的确存在截取 bug, 这用在交易系统,狂汗……
与老友话别后,迫不及待地从 GoogleFace 的一朵云中取回当年的 pad3 和 xxoo9 等代码,一测试,大惊:
pad3 不仅存在截取字符 bug, 居然还有性能问题……
一番激烈的思想斗争。
迷迷茫茫中,遥见唐僧笑侃而至:
世人皆笑我罗嗦,我道世人看不透。
欲解此惑看来时,质朴简单是真知。
唐僧抛下一卷轴,大笑而去:
/* 质朴长存法 */
function pad(num, n) {
var len = num.toString().length;
while(len < n) {
num = "0" + num;
len++;
}
return num;
}
观之,吾亦大笑,随唐僧取经去也……
注:一直想写这样一篇文章。今天闲逛 51js, 偶然看到一贴:位数不够前面补 0 的问题,于是立刻就有了这篇文章的构思。对于补零,我的奇淫反应是return Array(n - ("" + num).length + 1).join(0) + num;(也有 bug),和果果的类似,但考虑到震撼性(果果的 bug 更隐蔽),最后采用了果果的代码来举例。无论如何,感谢果果。

August 22nd, 2009 on 12:41
比较感兴趣那个xxoo函数
August 22nd, 2009 on 13:20
我评论也跟着update:
一些奇巧淫技着实让人看了拍案叫绝,大有“我怎么没想到”之功效,自己写出来的时候也无比暗爽,激动个好几天。殊不知埋下不少隐患。后人维护起来颇为困难,有种看不懂的感觉。
质朴长存法,赞。
大道至简,理性回归。我也反思一下。
August 22nd, 2009 on 13:21
这个mm比较搓,干吗要膜拜啊,这种奇技淫巧貌似本来就不能说明高还是不高,极其简单的逻辑非要写得弯弯绕,一眼看不出来问题,error-prone,大忌。
August 22nd, 2009 on 13:23
function pad4(num,n){
var s=”"+num, l=s.length;
return l>=n?s:new Array(n-l+1).join(“0″)+s;
};
这个函数比pad3稍快而无bug,不过比起平淡无奇法,还是自愧不如啊,pad是典型的大智若愚。
另外对于需要拼接巨型前缀,数组join仍比不上while循环,正在寻求原因,可能是拼接单个”0″仍显重量级不够。
另外觉得测试页面的效率比较过程有失精准,可待改进。
August 22nd, 2009 on 13:43
@闲耕:说说测试页面的效率问题。最后 for 的写法我故意继续奇淫技巧,但精确性上,我觉得没问题。
August 22nd, 2009 on 14:01
补充:
1. “” + num 和 num.toString() 的性能比较。相差很小,因此选择了更清晰语义化的 toString()
2. 除了 IE, 其它浏览器下,递归法的速度都更快。这是因为 JS 引擎的内部优化。感兴趣的请 google, 有不少相关资料。考虑清晰和语义性,以及 IE 的占有率,在这里,质朴长存法依旧胜出。
用空间换时间,还是用时间换空间,一切都是权衡。
August 22nd, 2009 on 14:33
关于递归,可以使用尾递归来优化。
关于效率比较,我觉得在计算完成之后再打印结果比较好。另外比较效率太常用,我们应该写一个合理的效率测试框架。
var _PAD=”00000000000000000000000000000000000000000000000000″;
function pad6(num, n){
var s=”"+num, l=s.length;
return l>=n?s:_PAD.substr(0,n-l+1)+s;
}
这是刚刚想到的一个高效实用的算法,虽然不能满足任意长度补零,但就实用性来讲基本够用了,不够的可以自行补充_PAD的长度。另外substr和substring,slice方法效率相当。
August 22nd, 2009 on 14:53
算了,还是写出来吧,怎么说也算是最快的算法,虽然没什么实用意义。我疯了,为这丁点的效率。
var _ARR_PAD=[];
for(var i=1; i=n?s:_ARR_PAD[n-l]+s;
}
August 22nd, 2009 on 14:56
。。。wp的评论的特殊字符看来要解决一下,大小于号,空白字符什么的
August 22nd, 2009 on 14:59
大道至简
August 22nd, 2009 on 15:26
function pad(num,n){return (”+num.length>=n)?num:pad(‘0′+num,n);}
这样子代码也蛮少的。
August 22nd, 2009 on 16:15
pad()最实用,也都看得明白
这pad2还好,只是递归,pad3,何必呢,苦了别人
团队里要是多几个喜欢这么写代码的就乱了
哈哈,不过还是篇好文章
August 22nd, 2009 on 18:04
要是都跟11楼那样写,真的得疯了……
而前不久我还喜欢那么写呢……
August 22nd, 2009 on 18:56
好文章!
pad3()这样的代码明显是给bug提供生存空间的
自己写起来容易错,别人看不容易明白,调试起来也麻烦
August 22nd, 2009 on 23:33
这个题目不错。学习了。
参考:
http://stackoverflow.com/questions/202605/repeat-string-javascript
http://blog.gugod.org/2007/09/string-repeat-in-javascript-and-as.html
http://www.webtoolkit.info/javascript-pad.html
August 22nd, 2009 on 23:50
//另一个奇技淫巧,前提: num 必须是整数
function pad5(num, n) {
if((num + ”).length >= n) {
return num
}
var s = num / Math.pow(10, n) + ”;
return s.replace(‘0.’, ”);
}
alert(pad5(123, 8));
August 23rd, 2009 on 8:01
其实这样的Bug应该算是逻辑上没考虑全面。
通过Math.max可以解决这个问题的。(性能另外考虑)
function pad(num, n) {
return Array(Math.max(0,(n+1)-(”+num).length)).join(0)+num;
}
August 23rd, 2009 on 10:30
以上pad5函数,基本不能用,因为Math对象默认采用科学计数法。
为此又一个奇技淫巧产生了:
function pad6(num, n) {
var l = (num + ”).length;
if(l >= n) {
return num;
}
var zero = 0;
return zero.toFixed(n-l).toString().replace(‘0.’, ”) + num;
}
August 23rd, 2009 on 13:58
很不错!
人生三境界:“看山是山,看水是水”,“看山不是山,看水不是水”,“看山又是山,看水又是水”。
August 23rd, 2009 on 16:31
很好很强大
August 24th, 2009 on 14:53
pad2使用递归感觉资源占用会比较大,每次都要压栈出栈。还有一个就是递归次数过多的时候容易出现堆栈溢出,如:pad2(1234567,10000);虽然测试数据感觉实际意义不是很大,但是能够看出递归带来的一些问题。
August 24th, 2009 on 20:44
function pad(num, n){
if((num+”").length>=n)return num;
return arguments.callee(“0″+num, n);
}
此方法与pad2无异,却少了函数名
我的一点愚见:
运行速度还要看浏览器内部怎么实现了。
August 24th, 2009 on 22:22
哈哈,当看到前面时我还想说些什么。
August 25th, 2009 on 10:02
代码,女人的裙子,要短的恰如其分,不能短的离谱,太短,容易被我这种色魔YY滴
August 25th, 2009 on 21:46
pad2以及22楼的尾递归还是不错的
August 26th, 2009 on 22:44
性能,可维护性,代码美观性
要折中…
August 27th, 2009 on 14:51
想请教下博主,看了下淘宝的CSS sprites,背景有几个都是png的,IE6下的png透明是如何解决的?用JS吗? 貌似没看到相关的代码。
August 27th, 2009 on 15:07
晕,还好我是写 CSS 的……
August 27th, 2009 on 15:08
晕..我想应该是使用的png8…
August 28th, 2009 on 14:34
0000012
我在chome上面居然有这个结果
123456789
0000012
123456789
0000012
3456789
pad time: 168
pad2 time: 77
pad3 time: 257
pad2还比pad快。
August 29th, 2009 on 16:45
题外话:成语奇技淫巧。
September 8th, 2009 on 0:55
性能总是有前提的,有时空间换时间才是最快的:
function pad99(num, n) {
var magicN = 100;//临界点
var result = “”;
if (n < magicN) {
var prefix = [
"0",
"00",
"000",
"0000",
"00000",
"000000",
"0000000",
"00000000",
"000000000",
"0000000000"
//...magicN个0
];
result = prefix[n] + num.toString();
}
else {
result = padx(num, n);
}
return result;
}
September 12th, 2009 on 4:11
這樣寫:
var pad = function() {
var padSize = 0;
var padChar = ”;
return function(num, n) {
var len = n – String(num).length;
if (len < padSize ) {
padSize = len + 64 ;
padChar = (new Array(padSize)).join(‘0′);
}
return padChar.substr(0, len) + num;
}
}();
December 15th, 2009 on 13:56
果真“奇淫技巧“
leave a reply