js你不知的那些基础问题-数值
1 整数和浮点数
JavaScript 语言的底层根本没有整数,所有数字都是小数(64位浮点数)。容易造成混淆的是,
某些运算只有整数才能完成,此时 JavaScript 会自动把64位浮点数,转成32位整数,然后再进行运算。
由于浮点数不是精确的值,所以涉及小数的比较和运算要特别小心。
0.1 + 0.2 === 0.3
// false
0.3 / 0.1
// 2.9999999999999996
(0.3 - 0.2) === (0.2 - 0.1)
// false
2 数值精度
JavaScript 浮点数的64个二进制位,从最左边开始,是这样组成的。
- 第1位:符号位,
0
表示正数,1
表示负数 - 第2位到第12位(共11位):指数部分
- 第13位到第64位(共52位):小数部分(即有效数字)
符号位决定了一个数的正负,指数部分决定了数值的大小,小数部分决定了数值的精度。
JavaScript 提供的有效数字最长为53个二进制位。
由于2的53次方是一个16位的十进制数值,所以简单的法则就是,JavaScript 对15位的十进制数都可以精确处理。
(-1)^符号位 * 1.xx...xx * 2^指数部分
3 数值范围
位浮点数的指数部分的值最大为2047,分出一半表示负数,
则 JavaScript 能够表示的数值范围为21024到2-1023(开区间),
超出这个范围的数无法表示
如果一个数大于等于2的1024次方,那么就会发生“正向溢出”,
即 JavaScript 无法表示这么大的数,这时就会返回Infinity
。
Math.pow(2, 1024) // Infinity
如果一个数小于等于2的-1075次方(指数部分最小值-1023,再加上小数部分的52位),
那么就会发生为“负向溢出”,即 JavaScript 无法表示这么小的数,这时会直接返回0。
Math.pow(2, -1075) // 0
以下两种情况,JavaScript 会自动将数值转为科学计数法表示,其他情况都采用字面形式直接表示。
(1)小数点前的数字多于21位。
1234567890123456789012
// 1.2345678901234568e+21
(2)小数点后的零多于5个。
// 小数点后紧跟5个以上的零,
// 就自动转为科学计数法
0.0000003 // 3e-7
4 特殊数值
4.1 正负零
JavaScript 内部实际上存在2个0
:一个是+0
,一个是-0
,
区别就是64位浮点数表示法的符号位不同。它们是等价的。
唯一有区别的场合是,+0
或-0
当作分母,返回的值是不相等的
(1 / +0) === (1 / -0) // false
4.2 NaN
(1)含义
NaN
是 JavaScript 的特殊值,表示“非数字”(Not a Number),
主要出现在将字符串解析成数字出错的场合。
0
除以0
也会得到NaN
。
0 / 0 // NaN
需要注意的是,NaN
不是独立的数据类型,而是一个特殊数值,
它的数据类型依然属于Number
,使用typeof
运算符可以看得很清楚
typeof NaN // 'number'
(2)运算规则
NaN
不等于任何值,包括它本身。
NaN === NaN // false
数组的indexOf
方法内部使用的是严格相等运算符,所以该方法对NaN
不成立。
[NaN].indexOf(NaN) // -1
NaN
在布尔运算时被当作false
。
Boolean(NaN) // false
NaN
与任何数(包括它自己)的运算,得到的都是NaN
。
NaN + 32 // NaN
NaN - 32 // NaN
NaN * 32 // NaN
NaN / 32 // NaN
4.3 Infinity
(1)含义
Infinity
表示“无穷”,用来表示两种场景。
一种是一个正的数值太大,或一个负的数值太小,无法表示;
另一种是非0数值除以0,得到Infinity
。
// 场景一
Math.pow(2, 1024)
// Infinity
// 场景二
0 / 0 // NaN
1 / 0 // Infinity
由于数值正向溢出(overflow)、负向溢出(underflow)和被0
除,
JavaScript 都不报错,所以单纯的数学运算几乎没有可能抛出错误。
Infinity
大于一切数值(除了NaN
),-Infinity
小于一切数值(除了NaN
)。
Infinity > 1000 // true
-Infinity < -1000 // true
Infinity
与NaN
比较,总是返回false
。
Infinity > NaN // false
-Infinity > NaN // false
Infinity < NaN // false
-Infinity < NaN // false
0乘以Infinity
,返回NaN
;0除以Infinity
,返回0
;Infinity
除以0,返回Infinity
。
0 * Infinity // NaN
0 / Infinity // 0
Infinity / 0 // Infinity
Infinity
加上或乘以Infinity
,返回的还是Infinity
。
Infinity + Infinity // Infinity
Infinity * Infinity // Infinity
Infinity
减去或除以Infinity
,得到NaN
。
Infinity - Infinity // NaN
Infinity / Infinity // NaN
5.与数值相关的全局方法
5.1 parseInt()
(1)基本用法
如果字符串的第一个字符不能转化为数字(后面跟着数字的正负号除外),返回NaN
。
parseInt('abc') // NaN
parseInt('.3') // NaN
parseInt('') // NaN
parseInt('+') // NaN
parseInt('+1') // 1
所以,parseInt
的返回值只有两种可能,要么是一个十进制整数,要么是NaN
。
对于那些会自动转为科学计数法的数字,parseInt
会将科学计数法的表示方法视为字符串,
因此导致一些奇怪的结果。
parseInt(1000000000000000000000.5) // 1
// 等同于
parseInt('1e+21') // 1
parseInt(0.0000008) // 8
// 等同于
parseInt('8e-7') // 8
(2)进制转换
parseInt
方法还可以接受第二个参数(2到36之间),表示被解析的值的进制,
返回该值对应的十进制数。默认情况下,parseInt
的第二个参数为10,即默认是十进制转十进制。
parseInt('1000') // 1000
// 等同于
parseInt('1000', 10) // 1000
如果第二个参数不是数值,会被自动转为一个整数。
这个整数只有在2到36之间,才能得到有意义的结果,超出这个范围,则返回NaN
。
如果第二个参数是0
、undefined
和null
,则直接忽略。
parseInt('10', 37) // NaN
parseInt('10', 1) // NaN
parseInt('10', 0) // 10
parseInt('10', null) // 10
parseInt('10', undefined) // 10
前面说过,如果parseInt
的第一个参数不是字符串,会被先转为字符串。
这会导致一些令人意外的结果。
parseInt(0x11, 36) // 43
parseInt(0x11, 2) // 1
// 等同于
parseInt(String(0x11), 36)
parseInt(String(0x11), 2)
// 等同于
parseInt('17', 36)
parseInt('17', 2)
上面代码中,十六进制的0x11
会被先转为十进制的17,再转为字符串。
然后,再用36进制或二进制解读字符串17
,最后返回结果43
和1
。
5.2 parseFloat()
如果字符串符合科学计数法,则会进行相应的转换。
parseFloat('314e-2') // 3.14
parseFloat('0.0314E+2') // 3.14
parseFloat
方法会自动过滤字符串前导的空格。
parseFloat('\t\v\r12.34\n ') // 12.34
如果参数不是字符串,或者字符串的第一个字符不能转化为浮点数,则返回NaN
。
parseFloat([]) // NaN
parseFloat('FF2') // 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
5.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({}) // true
// 等同于
isNaN(Number({})) // true
isNaN(['xzy']) // true
// 等同于
isNaN(Number(['xzy'])) // true
但是,对于空数组和只有一个数值成员的数组,isNaN
返回false
。
isNaN([]) // false
isNaN([123]) // false
isNaN(['123']) // false
5.4 isFinite()
isFinite
方法返回一个布尔值,表示某个值是否为正常的数值。
isFinite(Infinity) // false
isFinite(-Infinity) // false
isFinite(NaN) // false
isFinite(undefined) // false
isFinite(null) // true
isFinite(-1) // true
除了Infinity
、-Infinity
、NaN
和undefined
这几个值会返回false
,
isFinite
对于其他的数值都会返回true
文章内容转自 阮一峰老师 JavaScript教程 https://wangdoc.com/javascript/index.html