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 相关文章推荐
js 函数的执行环境和作用域链的深入解析
Nov 01 Javascript
浅谈angularJS 作用域
Jul 05 Javascript
原生JavaScript编写canvas版的连连看游戏
May 29 Javascript
Bootstrap组件系列之福利篇几款好用的组件(推荐)
Jun 23 Javascript
Angularjs上传文件组件flowjs功能
Aug 07 Javascript
基于Vue.js 2.0实现百度搜索框效果
Dec 28 Javascript
JS实现定时任务每隔N秒请求后台setInterval定时和ajax请求问题
Oct 15 Javascript
jQuery实现的淡入淡出与滑入滑出效果示例
Apr 18 jQuery
JS实现的哈夫曼编码示例【原始版与修改版】
Apr 22 Javascript
使用Mock.js生成前端测试数据
Dec 13 Javascript
Javascript中的奇葩知识,你知道吗?
Jan 25 Javascript
javascript中layim之查找好友查找群组
Feb 06 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
smarty实例教程
2006/11/19 PHP
深入phpMyAdmin的安装与配置的详细步骤
2013/05/07 PHP
php分页查询的简单实现代码
2017/03/14 PHP
thinkPHP5.0框架API优化后的友好性分析
2017/03/17 PHP
JS 分号引起的一段调试问题
2009/06/18 Javascript
jQuery MD5加密实现代码
2010/03/15 Javascript
xmlhttp缓存清除的2种解决方法
2013/12/13 Javascript
JS按回车键实现登录的方法
2014/08/25 Javascript
从JQuery源码分析JavaScript函数的apply方法与call方法
2014/09/25 Javascript
JQuery勾选指定name的复选框集合并显示的方法
2015/05/18 Javascript
JavaScript学习笔记之检测客户端类型是(引擎、浏览器、平台、操作系统、移动设备)
2015/12/03 Javascript
Bootstrap按钮组件详解
2016/04/26 Javascript
深入理解JavaScript中的对象复制(Object Clone)
2016/05/18 Javascript
vue.js表格组件开发的实例详解
2016/10/12 Javascript
easyui导出excel无法弹出下载框的快速解决方法
2016/11/10 Javascript
javascript设计模式之模块模式学习笔记
2017/02/15 Javascript
jquery mobile实现可折叠的导航按钮
2017/03/11 Javascript
jQuery编写textarea输入字数限制代码
2017/03/23 jQuery
JS 组件系列之Bootstrap Table的冻结列功能彻底解决高度问题
2017/06/30 Javascript
vue 指定组件缓存实例详解
2018/04/01 Javascript
发布Angular应用至生产环境的方法
2018/12/10 Javascript
判断JavaScript中的两个变量是否相等的操作符
2019/12/21 Javascript
基于vue.js仿淘宝收货地址并设置默认地址的案例分析
2020/08/20 Javascript
vue 解决在微信内置浏览器中调用支付宝支付的情况
2020/11/09 Javascript
python绘图方法实例入门
2015/05/19 Python
Python实现将罗马数字转换成普通阿拉伯数字的方法
2017/04/19 Python
Python实现对特定列表进行从小到大排序操作示例
2019/02/11 Python
OpenCV 轮廓检测的实现方法
2019/07/03 Python
Pandas 缺失数据处理的实现
2019/11/04 Python
python语言中有算法吗
2020/06/16 Python
html5中的input新属性range使用记录
2014/09/05 HTML / CSS
HTML5中drawImage用法分析
2014/12/01 HTML / CSS
创业计划书如何吸引他人眼球
2014/01/10 职场文书
关于运动会的稿件
2014/02/02 职场文书
2014年纳税评估工作总结
2014/12/23 职场文书
大学校园招聘会感想
2015/08/10 职场文书