JavaScript数值处理 + 小花样

数值处理

一、StringToNumber

字符到数字的类型转换,存在一个语法结构,支持十进制、二进制、八进制和十六进制比如:

+'30'		// 30
+'ob111'	// 7
+'0o13'		// 11
+'0xFF'		// 255

此外,JavaScript支持的字符串语法还包括正负号科学计数法,可以使用大写或者小写的e来表示:

+'1e3'		// 1000
+'-1e-2'	// -0.01

也可以使用函数Number来显式转换

Number('30')		// 30
Number('0b111')		// 7
Number('0o13')		// 11
Number('0xFF')		// 255
Number('1e3')		// 1000
Number('-1e-2')		// -0.01

特别要注意,表达式所产生的隐式调用并不引用window.Number属性来调用对应的程序,我会在以下(二)中详细解释这个问题。

需要注意的是,parseInt 和 parseFloat 并不使用这个转换,所以支持的语法跟这里不尽相同。这个问题在以下(三)中讨论

二、小花样:window.Number函数与内置Number

先来看一个例子:

以上例子说明window的Number属性是可覆写的(writable=true),下面对Number函数进行覆写(实质上是修改Number的指向):

覆写之后window.Number失去原有的特性:

(注意第二句new Number(123) 时自定义的return语句会被自动添加return this屏蔽)。但是覆写window.Number后我们还是可以使用以下隐式类型转换

这说明了:

  1. 覆写之前Number所指向的程序(记为X)并没有释放,而是继续存在,只修改了window.Number的指向后,无法再用Number属性找到X。但是,隐式类型转换使用的依旧是X,这说明底层c++保留有指向X的指针
  2. 隐式类型转换并没有调用Number()(否则这里应该就输出“覆盖后的Number”了), 准确地说,没有通过window的Number属性变量来对X寻址,而是通过内部的一个变量(假设记为innerNumber,C++不一定使用这个名字)来对X寻址。

数字类型的装箱操作也是使用innerNumber来寻址X,而非使用window.Number。利用装箱原理,我们可以找回X

这样,window.Number和innerNumber就都指向X了。

三、parseInt 和 parseFloat

在不传入第二个参数的情况下,parseInt只支持16进制前缀“0x”,而且会忽略非数字字符,也不支持科学计数法。

在一些古老的浏览器环境中,parseInt还支持0开头的数字作为8进制前缀,这是很多错误的来源。所以在任何环境下,都建议传入parseInt的第二个参数,而parseFloat则直接把原字符串作为十进制来解析,它不会引入任何的其他进制。

多数情况下,Number 是比 parseInt 和 parseFloat 更好的选择。

1. parseInt

parseInt 函数将其第一个参数转换为字符串,解析它,并返回一个整数或NaN。如果不是NaN,返回的值将是作为指定基数(基数)中的数字的第一个参数的整数。

例如:radix参数为10 将会把第一个参数看作是一个数的十进制表示,8 对应八进制,16 对应十六进制,等等。基数大于 10 时,用字母表中的字母来表示大于 9 的数字。例如十六进制中,使用 A F

如果parseInt的字符不是指定基数中的数字,则忽略该字符和所有后续字符,并返回解析到该点的整数值。parseInt将数字截断为整数值。允许使用前导空格和尾随空格。

一些数中可能包含e字符(例如6.022e23),使用parseInt去截取包含e字符数值部分会造成难以预料的结果。例如:

parseInt("6.022e23", 10); // 返回 6
parseInt(6.022e2, 10); // 返回 602

parseInt不应该用作 Math.floor()的替代品。

如果 parseInt 遇到了不属于radix参数所指定的基数中的字符那么该字符和其后的字符都将被忽略。接着返回已经解析的整数部分。parseInt 将截取整数部分。开头和结尾的空白符允许存在,会被忽略。

在基数为 undefined,或者基数为 0 或者没有指定的情况下,JavaScript 作如下处理:

  • 如果字符串 string 以"0x"或者"0X"开头, 则基数是16 (16进制).
  • 如果字符串 string 以"0"开头, 基数是8(八进制)或者10(十进制),那么具体是哪个基数由实现环境决定。ECMAScript 5 规定使用10,但是并不是所有的浏览器都遵循这个规定。因此,永远都要明确给出radix参数的值
  • 如果字符串 string 以其它任何值开头,则基数是10 (十进制)。

如果第一个字符不能被转换成数字,parseInt返回NaN

算术上, NaN 不是任何一个进制下的数。 你可以调用isNaN 来判断 parseInt 是否返回 NaNNaN 参与的数学运算其结果总是 NaN

将整型数值以特定基数转换成它的字符串值可以使用 intValue.toString(radix).

更多细节可在MDN查看:

parseInt

2. parseFloor

parseFloat

四、numberToString

在较小的范围内,数字到字符串的转换是完全符合你直觉的十进制表示。当Number绝对值较大或者较小时,字符串表示则是使用科学计数法表示的。这个算法细节繁多,我们从感性的角度认识,它其实就是保证了产生的字符串不会过长。

具体的算法,你可以去参考JavaScript的语言标准。由于这个部分内容,我觉得在日常开发中很少用到,所以这里我就不去详细地讲解了。

总结

对于window的7种基本数据类型对应的构造函数,如果这些构造可覆写,则隐式类型转换和装箱操作都不会通过window对象里对应的属性(如Number)来寻址目标程序块X,而是通过我们普通方法访问不到的变量来寻址目标程序块X

另外,我们可以利用装箱原理来访问程序块X

补充

箭头函数不能用作构造函数!!!

posted @ 2019-07-12 10:12  Wenksti  阅读(733)  评论(0编辑  收藏  举报