javascript parseInt 大改造


Posted in Javascript onSeptember 27, 2009

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

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

首先我必须感谢那些即使这个问题我强调过无数次,也依然反复重复类似错误的人们。
没有他们反复犯错的鼓励,或许我不会认真考虑这个问题的解决方案。
其次,必须感谢《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;
那么基于这次的经验,今后遇到类似的问题就可以考虑到用这种乾坤大挪移的方法去解决了。

Javascript 相关文章推荐
让焦点自动跳转
Jul 01 Javascript
点击广告后才能获得下载地址
Oct 26 Javascript
快速排序 php与javascript的不同之处
Feb 22 Javascript
JavaScript加强之自定义event事件
Sep 21 Javascript
Javascript全局变量var与不var的区别深入解析
Dec 09 Javascript
判断日期是否能跨月查询的js代码
Jul 25 Javascript
正则验证小数点后面只能有两位数的方法
Feb 28 Javascript
详解使用Typescript开发node.js项目(简单的环境配置)
Oct 09 Javascript
vue 使用eventBus实现同级组件的通讯
Mar 02 Javascript
vue项目开发中setTimeout等定时器的管理问题
Sep 13 Javascript
jQuery事件绑定和解绑、事件冒泡与阻止事件冒泡及弹出应用示例
May 13 jQuery
浅谈JS中this在各个场景下的指向
Aug 14 Javascript
网页自动跳转代码收集
Sep 27 #Javascript
JavaScript中Object和Function的关系小结
Sep 26 #Javascript
js 覆盖和重载 函数
Sep 25 #Javascript
用Javascript 获取页面元素的位置的代码
Sep 25 #Javascript
Javascript 两个窗体之间传值实现代码
Sep 25 #Javascript
jQuery 使用手册(七)
Sep 23 #Javascript
jQuery 使用手册(六)
Sep 23 #Javascript
You might like
了解Joomla 这款来自国外的php网站管理系统
2010/03/11 PHP
php+ajax实现文章自动保存的方法
2014/12/30 PHP
php实现PDO中捕获SQL语句错误的方法
2017/02/16 PHP
jQuery获取地址栏参数插件(模仿C#)
2010/10/26 Javascript
jquery 回车事件实现代码
2011/08/23 Javascript
javascript 利用Image对象实现的埋点(某处的点击数)统计
2012/12/28 Javascript
jquery DIV撑大让滚动条滚到最底部代码
2013/06/06 Javascript
jQuery中的read和JavaScript中的onload函数的区别
2014/08/27 Javascript
一个JavaScript递归实现反转数组字符串的实例
2014/10/14 Javascript
2014年最火的Node.JS后端框架推荐
2014/10/27 Javascript
JavaScript中的object转换函数toString()与valueOf()介绍
2014/12/31 Javascript
全面解析Bootstrap中tab(选项卡)的使用方法
2016/06/06 Javascript
浅谈Javascript中的函数、this以及原型
2016/10/09 Javascript
使用jQuery,Angular实现登录界面验证码详解
2017/04/27 jQuery
JS库之Highlight.js的用法详解
2017/09/13 Javascript
jQueryMobile之窗体长内容的缺陷与解决方法实例分析
2017/09/20 jQuery
vue中路由验证和相应拦截的使用详解
2017/12/13 Javascript
vuejs中监听窗口关闭和窗口刷新事件的方法
2018/09/21 Javascript
简单说说如何使用vue-router插件的方法
2019/04/08 Javascript
支付宝小程序实现省市区三级联动
2020/06/21 Javascript
vue实现井字棋游戏
2020/09/29 Javascript
Python的标准模块包json详解
2017/03/13 Python
python面向对象_详谈类的继承与方法的重载
2017/06/07 Python
Django原生sql也能使用Paginator分页的示例代码
2017/11/15 Python
Python之两种模式的生产者消费者模型详解
2018/10/26 Python
python列表插入append(), extend(), insert()用法详解
2019/09/14 Python
使用python实现男神女神颜值打分系统(推荐)
2019/10/31 Python
Python中过滤字符串列表的方法
2020/12/22 Python
Python实现邮件发送的详细设置方法(遇到问题)
2021/01/18 Python
Html5页面内使用JSON动画的实现
2019/01/29 HTML / CSS
个人优缺点自我评价
2014/01/27 职场文书
咖啡店创业计划书范文
2014/09/15 职场文书
圣诞节开幕词
2015/01/29 职场文书
民间借贷纠纷起诉书
2015/08/03 职场文书
小学英语教学经验交流材料
2015/11/02 职场文书
Python读取和写入Excel数据
2022/04/20 Python