javascript parseInt 大改造

还隐约记得得知了来龙去脉,为自己掌握了一个经验而欢呼雀跃。

还隐约记得被这同一问题折磨了无数次后,无奈与痛下决心的心境。

首先我必须感谢那些即使这个问题我强调过无数次,也依然反复重复类似错误的人们。
没有他们反复犯错的鼓励,或许我不会认真考虑这个问题的解决方案。
其次,必须感谢《JavaScript高级程序设计》的作者和译者。
在这里我得到了解决该问题的启示,不然我依然要每每强调使用parseInt时应注意什么。

同时,希望在这里不仅仅留下一个解决方案。
解决问题的思路与想法,以及对问题举一反三的经验在这里保留一下。

问题:
很久以前发生的问题不想再痛苦的回忆。
这次的问题很简单。两个月份比较的时候,因为月份是从字符串中抽取出来的, 于是用parseInt转换了一下。
结果parseInt("08")之后结果是 0
原因请参看以下《JavaScript高级程序设计》19~20页对 parseInt函数的讲解。

parseInt() 方法还有基模式,可以把二进制、八进制、十六进制或其他任何进制的字符串转换成整数。
基是由 parseInt() 方法的第二个参数指定的,所以要解析十六进制的值,需如下调用 parseInt() 方法:


代码如下:

var iNum1 = parseInt("AF", 16); //返回 175

当然,对二进制、八进制甚至十进制(默认模式),都可以这样调用 parseInt() 方法:


代码如下:

var iNum1 = parseInt("10", 2); //返回 2
var iNum2 = parseInt("10", 8); //返回 8
var iNum3 = parseInt("10", 10); //返回 10

如果十进制数包含前导 0,那么最好采用基数 10,这样才不会意外地得到八进制的值。例如:

var iNum1 = parseInt("010"); //返回 8
var iNum2 = parseInt("010", 8); //返回 8
var iNum3 = parseInt("010", 10); //返回 10

在这段代码中,两行代码都把字符 "010" 解析成一个数字。

第一行代码把这个字符串看作八进制的值,解析它的方式与第二行代码(声明基数为 8)相同。最后一行代码声明基数为 10,所以 iNum3 最后等于 10。

初试身手:
以前的解决方法是让大家都抛弃 parseInt函数,全部以parseFloat来替换。
但是作为人“孰能无忘”?
最好的办法莫过于保留parseInt的“形”,废了parseInt的“神”。
于是我想到了《JavaScript高级程序设计》87~88页关于“重定义已有方法”的说明。
3.6.2 重定义已有方法
就像能给已有的类定义新方法一样,也可重定义已有的方法。
如前一章所述,函数名只是指向函数的指针,因此可以轻易地使它指向其他函数。如果修改了本地方法,如 toString() ,会出现什么情况呢?

Function.prototype.toString = function () {
return "Function code hidden";
}
前面代码完全合法,运行结果完全符合预期:
function sayHi () {
alert("你好!");
}
alert(sayHi.toString()); //输出"Function code hidden"
也许你还记得,第 2 章中介绍过 Function 的 toString() 方法通常输出的是函数的源代码。
覆盖该方法,可以返回另一个字符串(在这个例子中,返回 "Function code hidden " )。
不过, toString() 指向的原始函数怎样了呢?它将被无用存储单元回收程序回收,因为它被完全废弃了。
没能够恢复原始函数的办法,所以在覆盖原始方法前,存储它的指针比较安全,以便以后的使用。
你甚至可能在某种情况下在新方法中调用原始方法:
Function.prototype.originalToString = Function.prtotype.toString;
Function.prototype.toString = function () {
if(this.originalToString().length >100) {
return "Function too leng to display."
} else {
return this.originalToString();
}  
在这段代码中,第一行代码把对当前 toString() 方法的引

用保存在属性 originalTo- String 中。然后用定制的方法覆盖了 toString() 方法。
新方法将检查该函数源代码的长度是否大于 100 。
如果是,就返回错误消息,说明该函数代码太长,否则调用 originalToString() 方法,返回函数的源代码。

根据这个例子,只要照葫芦画瓢写一行
Global.prototype.parseInt = Global.prototype.parseFloat;
那么 parseInt函数真的就变成徒有其表,肚子里面干的却是parseFloat勾当的函数了。
但是,同时一个致命的问题点也摆在眼前。
那就是JavaScript中的Global对象,就跟神一样, 只是个概念。
说明请参见下面《JavaScript高级程序设计》70页关于“内置对象”的说明。
Global对象是ECMAScript中最特别的对象,因为实际上它根本不存在。
如果尝试编写下面的代码,将得到错误:
var pointer = Global;
错误消息显示Global不是对象,但刚才不是说Global是对象吗?
没错。这里需要理解的主要概念是,在ECMAScript中,不存在独立的函数,所有函数都必须是某个对象的方法。
本书前面介绍的函数,如isNaN()、isFinite()、parseInt()和parseFloat()等,看起来都像独立的函数。
实际上,它们都是Global对象的方法。

于是,上网大查怎样获取Global对象,或怎么使用Global.prototype来改变parseInt函数。
结果可想而知,神就是神,就连著名的“搜神网”Google也查不出来。
欲放弃之时,果然应了那句“死地而后生”。突然想到parseInt就像个全局函数一样,根本不用什么对象调用。
那是不是说,只要把上面那句改成 parseInt = parseFloat;就可以了?
果然,神,无处不在!!! 好用了!!!

深度考究:
问题基本上解决了。只有一点需要注意的,就是JavaScript加载出错的时候,后面的语句就不加载执行了。
所以这句一定要放在第一句执行。现在正好建一个JavaScript通用方法库,要求以后每个页面必须引入该库文件。
所以这一句放在该JavaScript通用方法库的第一行,从此便可高枕无忧。
但是当我在为该段代码写注释,特别是列举如何应用时,发现如下代码的问题
alert(parseInt("010", 2)); //10
alert(parseInt("010", 8)); //10
alert(parseInt("010", 10)); //10
每一个处理的返回值都是10,也就是说可以处理二进制,八进制,十六进制的parseInt从此消失了。
如果说单个参数的parseInt惹出了不少麻烦,我们对于没有惹祸的两个参数的parseInt还是希望保留其特异功能的。
于是需要进一步的改进。
那么就要根据使用parseInt函数时,传递参数的个数来进行判断处理。
如果只有一个参数,那么就调用parseFloat返回结果。
如果有两个以上的参数,那么就调用parseInt两个参数的处理,返回结果。
这里判断参数个数用到arguments对象,参见《JavaScript高级程序设计》53~54页关于arguments对象的说明。
在函数代码中,使用特殊对象 arguments,开发者无需明确指出参数名 ,就能访问它们。
例如,在函数 sayHi() 中,第一个参数是 message。
用 arguments[0] 也可以访问这个值,即第一个参数的值(第一个参数位于位置 0,第二个参数位于位置 1,依此类推)。
因此,无需明确命名参数,就可以重写函数:
function sayHi() {
if (arguments[0] == "bye") {
return;
}
alert(arguments[0]);
}
于是就有了如下代码:
originalparseInt = parseInt;
parseInt = function (){
if(arguments.length == 1){
return parseFloat(arguments[0]);
} else {
return originalparseInt(arguments[0], arguments[1]);
}
这段代码里我们改造了parseInt,让其通过参数个数的不同进行不同的处理。
用一个新的变量originalparseInt保留了parseInt的原型。
这样我们即便改造了parseInt,依然能通过保留的原型变量originalparseInt使用parseInt的原始功能。

返璞归真:
代码写到这本以为一切都OK了,却被人说彻底抹杀了parseInt函数对2进制,8进制的处理。
想想也是。处理的过于极端,只想着用parseFloat彻底替换掉讨厌的parseInt函数。
如果我们正的用到2进制或8进制的数字转换,还得用我们费劲保留的parseInt函数的原型新变量originalparseInt。
其实我们的愿望很简单。
parseInt函数中只有一个参数的时候就想让它简单的处理10进制的转换,别再因为首位的0来产生一些头疼的bug。
当我们用到第二个参数,想让它处理2进制,8进制的时候,我还依然能用parseInt既存的功能。
于是有了下面最终的代码:
考虑到js文件体积的问题,尽量减少代码量。于是把 originalparseInt 换成了 $parseInt。
另外把超级长的内置对象名arguments直接换成了一个字母 a 这样该对象用了4次节省的代码量就非常可观了。

举一反三:
对parseInt函数的再造就完成了。
那么其实我们可以根据这次改造的经验,改造与parseInt具有类似的烦人特性的JavaScript方法。
譬如,escape,unescape这种已经被 W3C组织不推荐使用的方法就可以用被推荐的方法替换掉

escape = encodeURI;
unescape = decodeURI;
那么基于这次的经验,今后遇到类似的问题就可以考虑到用这种乾坤大挪移的方法去解决了。

(0)

相关推荐

  • javascript parseInt与Number函数的区别

    但是parseInt("08", 10)是可以返回8的. 为搞清楚两者的区别, 参考了别人写的parseInt&Number的区别: parseInt Parses a string argument and returns an integer of the specified radix or base. 核心函数 实现版本 Navigator 2.0: If the first character of the string specified in parseInt(s

  • 详解js中Number()、parseInt()和parseFloat()的区别

    一:Number() 如果是Boolean值,true和false值将分别被转换为1和0. 如果是数字值,只是简单的传入和返回. 如果是null值,返回0. 如果是undefined,返回NaN. 如果是字符串: a.  如果字符串中只包含数字时,将其转换为十进制数值,忽略前导0 b. 如果字符串中包含有效浮点格式,如"1.1",将其转换为对应的浮点数字,忽略前导0 c. 如果字符串中包含有效的十六进制格式,如"0xf",将其转换为相同大小的十进制数值 d. 如果字

  • js parseInt的陷阱分析小结

    复制代码 代码如下: var a = parseInt("09"), b = Number("09"); 很多人会认为a和b的值都是数字9,但实际上不是. parseInt的主要作用是把字符串转换为整数,或者把小数转换为整数.一般情况下,我们只用到它的第一个参数.但实际上,它有两个参数: parseInt(string, radix) parseInt会根据radix指定的进制进行转换,比如: 复制代码 代码如下: alert(parseInt("10&q

  • javascript中parseInt()函数的定义和用法分析

    本文实例讲述了javascript中parseInt()函数的定义和用法.分享给大家供大家参考.具体分析如下: 此函数可以解析一个字符串,并返回一个整数. 语法结构: 复制代码 代码如下: parseInt(string, type) 参数列表: 参数 描述 string 必需.要被解析的字符串. type 可选.表示要解析的数字的基数,通俗的说就是数字的进制,比如二进制.八进制或者十六进制.该值介于2 ~ 36之间. 详细说明: 一.指定type参数: 指定type参数后,函数就会按照指定的t

  • JavaScript的parseInt 取整使用

    Java 也有 Integer.parseInt() 方法, 但是 JavaScript 的 parseInt 处理方式与 Java 等强整型语言不太一样, 所以经常有人因为对这个方法的使用不当而获得异常返回. 下面是一段 Java 代码, 用于将字符串 020 转为整型. 复制代码 代码如下: public class Test { public static void main(String args[]) throws Exception { String str = "020"

  • JS实现手写parseInt的方法示例

    前言 本文主要给大家介绍了关于JS实现手写parseInt的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 手写parseInt的实现:要求简单一些,把字符串型的数字转化为真正的数字即可,但不能使用JS原生的字符串转数字的API,比如Number() 示例代码 function _parseInt(str, radix) { let str_type = typeof str; let res = 0; if (str_type !== 'string' &&

  • js中parseInt函数浅谈

    从很热门的实例parseInt("09")==0说起.parseInt(number,type)这个函数后面如果不跟第2个参数来表示进制的话,默认是10进制.比如说parseInt("010",10)就是10进制的结果:10,parseInt("010",2)就是2进制的结果:2,parseInt("010",8)就是8进制的结果:8,parseInt("010",16)就是2进制的结果:16. 下面我来说

  • 关于javascript中的parseInt使用技巧

    要对表单中填写的日期格式进行客户端验证,于是在网上找了段代码,其中用到parseInt对年月日做判断,其中有类似这样的语句: ...... else if(parseInt(month)<1 || parseInt(month) >12) ...... 可是对于当前本来正确的日期,这里怎么也通不过.后来一查才明白,parseInt实际上有两个参数,第一个是要转换的值,第二个是指定的进制.如果不指定第二个参数,那么它只能正确地转换01到07(即把它们转换成1到7),从08开始,它就会按照&quo

  • javascript parseInt 函数分析(转)

    javascript的parseInt函数 javascript的parseInt函数,大家都知道是干啥的 但你知道 parseInt("07") 返回多少 ? parseInt("08") 又返回多少 ? 正确答案是 parseInt("07") 返回8 parseInt("08") 返回0 你知道问题在哪? 其实,这个问题可能大家都没想过吧. 用javascript的parseInt函数时, parseInt("

  • javascript中的parseInt和parseFloat区别

    先看代码: 复制代码 代码如下: <script> alert(parseInt("3.54 apples")); alert(parseFloat("3.54 apples")); </script> <script>alert(parseInt("3.54 apples"));alert(parseFloat("3.54 apples"));</script> 运行结果: p

随机推荐