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 相关文章推荐
jQuery 遍历json数组的实现代码
Sep 22 Javascript
js新闻滚动 js如何实现新闻滚动效果
Jan 07 Javascript
jQuery拖动图片删除示例
May 10 Javascript
Asp.Net alert弹出提示信息的几种方法总结
Jan 29 Javascript
Jq通过td获取同行其它列td的方法
Oct 05 Javascript
实现JavaScript高性能的数据存储
Dec 11 Javascript
JavaScript利用正则表达式替换字符串中的内容
Dec 12 Javascript
vue 插值 v-once,v-text, v-html详解
Jan 19 Javascript
vue和webpack安装命令详解
Jun 15 Javascript
详解Vue源码学习之callHook钩子函数
Jul 25 Javascript
Vue 数据绑定的原理分析
Nov 16 Javascript
javascript实现点击产生随机图形
Jan 25 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
PHP闭包(Closure)使用详解
2013/05/02 PHP
php上传excel表格并获取数据
2017/04/27 PHP
php中访问修饰符的知识点总结
2019/01/27 PHP
JavaScript中的new的使用方法与注意事项
2007/05/16 Javascript
javascript 特殊字符串
2009/02/25 Javascript
基于Jquery的动态添加控件并取值的实现代码
2010/09/24 Javascript
javascript中window.event事件用法详解
2012/12/11 Javascript
Javascript改变CSS样式(局部和全局)
2013/12/18 Javascript
jquery判断小数点两位和自动删除小数两位后的数字
2014/03/19 Javascript
jQuery简单几行代码实现tab切换
2015/03/10 Javascript
js数组依据下标删除元素
2015/04/14 Javascript
微信小程序使用第三方库Underscore.js步骤详解
2016/09/27 Javascript
vue多级多选菜单组件开发
2020/09/08 Javascript
JS实现全屏的四种写法
2016/12/30 Javascript
Node.js中sequelize时区的配置方法
2017/12/10 Javascript
浅谈Vuejs中nextTick()异步更新队列源码解析
2017/12/31 Javascript
vue 子组件向父组件传值方法
2018/02/26 Javascript
解决Mac下安装nmp的淘宝镜像失败问题
2018/05/16 Javascript
Vue2.0仿饿了么webapp单页面应用详细步骤
2018/07/08 Javascript
Jquery属性的获取/设置及样式添加/删除操作技巧分析
2019/12/23 jQuery
vue点击标签切换选中及互相排斥操作
2020/07/17 Javascript
[06:24]DOTA2 2015国际邀请赛中国区预选赛第二日TOP10
2015/05/27 DOTA
[42:32]完美世界DOTA2联赛PWL S2 LBZS vs FTD.C 第二场 11.27
2020/12/01 DOTA
Python动态加载模块的3种方法
2014/11/22 Python
Python实现测试磁盘性能的方法
2015/03/12 Python
python opencv实现图像边缘检测
2019/04/29 Python
pandas 空数据处理方法详解
2019/11/02 Python
keras中的loss、optimizer、metrics用法
2020/06/15 Python
Python过滤序列元素的方法
2020/07/31 Python
python+selenium自动化实战携带cookies模拟登陆微博
2021/01/19 Python
python 实现有道翻译功能
2021/02/26 Python
浅谈Html5页面打开app的一些思考
2020/03/30 HTML / CSS
Python如何定义一个函数
2015/09/01 面试题
2014优秀党员事迹材料
2014/08/14 职场文书
查摆问题自查报告范文
2014/10/13 职场文书
初三学生语文考试作弊检讨书
2014/12/14 职场文书