《JavaScript入门经典(第4版)》上第5章一个实例程序的修正,完善

 

今日,做《JavaScript入门经典(第4版)》第5章上的一个例题,感觉书上的代码有个小错误。

这是ch5_examp5.html上的一个实例,是计算一个数x保留y小数位后,四舍五入的结果是什么。

代码如下:

   1: <script type="text/javascript">
   2:  
   3: function fix(fixNumber, decimalPlaces)
   4: {
   5:     var div = Math.pow(10,decimalPlaces);
   6:     fixNumber = Math.round(fixNumber * div) / div;
   7:     return fixNumber;
   8: }
   9: </script>
  10: </head>
  11: <body>
  12: <script type="text/javascript">
  13:  
  14: var number1 = prompt("Enter the number with decimal places you want to fix","");
  15: var number2 = prompt("How many decimal places do you want?","");
  16:  
  17: document.write(number1 + " fixed to " + number2 + " decimal places is: ");
  18: document.write(fix(number1,number2));
  19:  
  20: </script>

 

但这个代码运行后有个问题,就是如果输入1.995,要求保留2个小数位,但结果却是“2”,原因在于在用pow()方法乘以原数字并用Math.round()方法后,这样的情况会出现尾数为“0”的情况,再除以10,100这样的,就不能保留我们希望保留的小数位了。

因此,书上的代码是有问题,我捉摸了一下,可以对原有代码做个修正,加一个if判断,如果尾数为0,则说明这种情况出现了,需要进行修正。新的代码如下:

 

   1: <script type = "text/javascript">
   2:             function deci(x,y){
   3:                 var a = x*(Math.pow(10,y));
   4:                 x = (Math.round(a)) / (Math.pow(10,y));
   5:                 var z = new String(Math.round(a)); // 创建一个新变量z,将Math.round(a)转为字符串类型,这样就可以用charAt方法判断字符串的最后一位是否为0)
   6:                 if (z.charAt(z.length-1) ==0) //如果变量z的最后一位为0,则说明除以10*y后,会变成整数,不保留小数位,所以要用toFixed方法强制保留小数位;
   7:                      {
   8:                      var u = new Number(x); //创建一个新变量u,将x转为Number类型,这样就可以调用toFixed方法
   9:                      var t = u.toFixed(y);  //创建一个新变量t,将u取小数位y位;
  10:                      return t;
  11:                      }
  12:                 else
  13:                 return x;
  14:             }
  15:             var X1 = prompt("please input x", "");
  16:             var Y1 = prompt("please input y","");
  17:             
  18:             document.write(deci(X1,Y1));
  19:         </script>

 

这个解决方案比较复杂,需要先创建一个新变量z,将原数据变量类型转为字符串,才好使用charAt方法去获取最后一个字符值(我试了,charAt方法,只能用于字符串类型),然后进行条件判断,如果变量z最后一位是0,则需要将变量x先转为Number类型,再使用toFixed方法,强制赋予y位的小数位。

但这个解决方案,也不是很好,简单的问题,搞得这么复杂,中间涉及大量数据转换乃至数据类型转换,如果不是为了学知识,仅是从算法而言,是在不符合“简单为美”的原则。后来想到既然将简单数值型变量,用new Number方法转为Number对象后,就可以使用toFixed()方法了,为何还要使用pow()方法+round()方法的方式去处理?可以直接转换成Number对象再强制保留小数位即可。代码优化后如下,执行结果完全无问题。

 

   1: <script type = "text/javascript">
   2:             function deci(x,y){
   3:                 var a = new Number(x); //将变量x转换为Number对象类型,这样就可以使用toFixed()方法了
   4:                 var b = a.toFixed(y);  //toFixed()方法,可以实现按规定小数位四舍五入
   5:                 return b; 
   6:             }
   7:             var X1 = prompt("please input x", "");
   8:             var Y1 = prompt("please input y","");
   9:             
  10:             document.write(deci(X1,Y1));
  11:         </script>

 

补充:

 

奇怪的是,最后一个代码,如果输入0.95和1.95这样的数字,取1位小数的四舍五入,结果应该是1.0、2.0,在ie9浏览器上,结果确实如此,但在firefox和chrome浏览器,都输出成0.9和1.9,而2.95就不存在这样的问题了。不知何故?

 

而运行第2段那个比较复杂的代码,则以上3个浏览器,都能完美计算四舍五入后的结果。

 

网上找到一篇文章,看来可能是toFixed()方法的一个bug造成的。

 

转载如下,这个代码还看不懂,以后再看吧:

原文网址:http://ahailu.blog.163.com/blog/static/833716120097104825237/


在JS中四舍五入的函数 toFixed(n) , n为要保留的小数位数。

n为0~20,当n超过20的时候,JS会出错。

var d=10.005;

var f=d.toFixed(2);

alert(f);

bug:

如果小数点前和要截取的前一位都是0时,不会按常理截取。

var h=0.07

h.toFixed(1)的值为0.0

如果要修改这个缺陷,可以把js中的Number类型的toFixed方法重写。

例如:

   1:  
   2: Number.prototype.toFixed = function(d)
   3: {
   4: var s=this+"";if(!d)d=0;
   5: if(s.indexOf(".")==-1)s+=".";s+=new Array(d+1).join("0");
   6: if (new RegExp("^(-|\\+)?(\\d+(\\.\\d{0,"+ (d+1) +"})?)\\d*$").test(s))
   7: {
   8: var s="0"+ RegExp.$2, pm=RegExp.$1, a=RegExp.$3.length, b=true;
   9: if (a==d+2){a=s.match(/\d/g); if (parseInt(a[a.length-1])>4)
  10: {
  11: for(var i=a.length-2; i>=0; i--) {a[i] = parseInt(a[i])+1;
  12: if(a[i]==10){a[i]=0; b=i!=1;} else break;}
  13: }
  14: s=a.join("").replace(new RegExp("(\\d+)(\\d{"+d+"})\\d$"),"$1.$2");
  15: }if(b)s=s.substr(1);return (pm+s).replace(/\.$/, "");} return this+"";
  16: }; 

这样就可以修复Number类型的toFixed方法。

posted on 2011-11-24 08:20  CDDF  阅读(202)  评论(0编辑  收藏  举报