阅读 0

JavaScript 基本数据类型--数值

1 整数和浮点数

在JavaScript内部,所有数字都是以64位浮点数类型来存储的,即使整数也是如此,因此 1 和 1.0 是一样的,是同一个数 1 === 1.0 返回true。

由于浮点数不是精确的值,所以涉及到小数的运算要特别小心。

2 数值精度

根据国际标准 IEEE 754,JavaScript浮点数的64个二进制位,从最左边开始,这样组成的:

  • 第1位: 符号位,0表示正数,1表示负数,决定了一个数的正负
  • 第2位到第12位(共11位):指数部分,决定了数值的大小
  • 第13位到第64位(共52位):小数部分(有效数字),决定了数值的精度

指数部分一共有11个二进制位,因此大小范围就是0到2047。IEEE 754 规定,如果指数部分的值在0到2047之间(不含两个端点),那么有效数字的第一位默认总是1,不保存在64位浮点数之中。也就是说,有效数字这时总是1.xx...xx的形式,其中xx..xx的部分保存在64位浮点数之中,最长可能为52位。因此,JavaScript 提供的有效数字最长为53个二进制位。

(-1)^符号位 * 1.xx...xx * 2^指数部分
复制代码

上面公式是正常情况下(指数部分在0到2047之间),一个数在 JavaScript 内部实际的表示形式。

精度最多只能到53个二进制位,这意味着,绝对值小于2的53次方的整数,即-253到253,都可以精确表示。

一段著名的代码,为什么在 为什么在 JavaScript 中,0.1+0.2 不能 =0.3, 浮点数运算的精度问题导致等式左右的结果并不是严格相等,而是相差了个微小的值。

所以实际上,这里错误的不是结论,而是比较的方法,正确的比较方法是使用 JavaScript 提供的最小精度值:

  console.log( Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON);
复制代码

3 特殊数值

3.1 正零和负零

JavaScript 内部实际上存在2个0:一个是+0,一个是-0,区别就是64位浮点数表示法的符号位不同。它们是等价的。

-0 === +0 // true
0 === -0 // true
0 === +0 // true
复制代码

几乎所有场合,正零和负零都会被当作正常的0。唯一有区别的场合是,+0或-0当作分母,返回的值是不相等的。除以正零得到+Infinity,除以负零得到-Infinity,这两者是不相等的

3.2 NaN

3.2.1 含义

NaN是JavaScript的特殊值(not a number),主要是出现在将字符串转换为数字出错的情况下。

5 - 'x' // NaN
复制代码

上面代码运行时,会自动将字符串x转为数值,但是由于x不是数值,所以最后得到结果为NaN,表示它是“非数字”(NaN)。

0除以0也会得到NaN。

需要注意的是 NaN不是独立的数据类型,而是一个特殊数值,它的数据类型依然属于Number,typeof NaN 的结果是 'number'

3.2.2 运算规则

NaN不等于任何值,包括它自身

NaN === NaN // false
复制代码

数组的indexOf内部执行的事全等的操作运算,所以该方法对NaN不成立。

[NaN].indexOf(NaN) // -1
复制代码

NaN在布尔运算时被当作false。

NaN与任何数(包括它自己)的运算,得到的都是NaN。

3.3 Infinity

Infinity 表示无穷,一个是正无穷,一个是负无穷。

Infinity 发生的情况一个是表达式的计算结果太大,超出了能够表示的范围,另一个是非0数值除以0,会返回Infinity。

Infinity有正负之分,Infinity表示正的无穷,-Infinity表示负的无穷。

4 与数值相关的全局方法

4.1 parseInt

parseInt用于将字符串转换为整数

parseInt('123') // 123
复制代码

字符串转为整数的时候,是一个个字符依次转换,如果遇到不能转为数字的字符,就不再进行下去,返回已经转好的部分。

parseInt('8a') // 8
parseInt('12**') // 12
复制代码

如果字符串的第一个字符不能转化为数字(后面跟着数字的正负号除外),返回NaN。

parseInt('abc') // NaN
parseInt('.3') // NaN
parseInt('') // NaN
parseInt('+') // NaN
parseInt('+1') // 1
复制代码

所以,parseInt的返回值只有两种可能,要么是一个十进制整数,要么是NaN。

如果字符串以0x或0X开头,parseInt会将其按照十六进制数解析。

parseInt('0x10') // 16
复制代码

如果字符串以0开头,将其按照10进制解析。

parseInt('011') // 11
复制代码

parseInt方法还可以接受第二个参数(2到36之间),表示被解析的值的进制,返回该值对应的十进制数。默认情况下,parseInt的第二个参数为10,即默认是十进制转十进制。

parseInt('1000', 2) // 8
parseInt('1000', 6) // 216
parseInt('1000', 8) // 512
复制代码

4.2 parseFloat

parseFloat 用于将一个字符串转化为浮点数

如果字符串符合科学计数法,则会进行相应的转换。

parseFloat('314e-2') // 3.14
parseFloat('0.0314E+2') // 3.14
复制代码

如果字符串包含不能转为浮点数的字符,则不再进行往后转换,返回已经转好的部分。

parseFloat('3.14more non-digit characters') // 3.14
复制代码

如果参数不是字符串,或者字符串的第一个字符不能转化为浮点数,则返回NaN。

parseFloat([]) // NaN
parseFloat('FF2') // NaN
parseFloat('') // NaN
复制代码

上面代码中,尤其值得注意,parseFloat会将空字符串转为NaN。

这些特点使得parseFloat的转换结果不同于Number函数。

parseFloat(true)  // NaN
Number(true) // 1

parseFloat(null) // NaN
Number(null) // 0

parseFloat('') // NaN
Number('') // 0

parseFloat('123.45#') // 123.45
Number('123.45#') // NaN
复制代码

4.3 isNaN

isNaN可以用来判断一个值是不是NaN

isNaN(NaN) // true
isNaN(123) // false
复制代码

但是isNaN只对数值有效,如果传入其它的值,会被先转成数值,然后再进行判断。比如传入字符串的时候,字符串会先被转换成数值得到的是NaN,所以最后返回的是true。也就是说isNaN为true的时候,可能不是NaN,也可能是一个字符串或者其它类型的值。

isNaN('Hello') // true
// 相当于
isNaN(Number('Hello')) // true

isNaN({}) // true
// 等同于
isNaN(Number({})) // true
复制代码

但是对于空数组和只有一个数值成员的数组来说,isNaN返回false,这是因为这些数组能被Number函数转换成数值

isNaN([]) // false
isNaN([123]) // false
isNaN(['123']) // false
复制代码

因此判断一个值是不是NaN,可以用下面的两种方法。

  • 使用isNaN方法
function myIsNaN(value) {
  return typeof value === 'number' && isNaN(value);
}
复制代码
  • 判断自身是否相等
function myIsNaN(value) {
  return value !== value;
}
复制代码
  • es6方法 Number.isNaN()
Number.isNaN('abc'); // false
复制代码
关注下面的标签,发现更多相似文章
评论