前面那个部分介绍的比较简单,这样容易理解一点,接下来就可以来看看稍稍复杂一些的类型了:
1. 布尔值
只有true(真)和false(伪)两个固定值的数据类型,本能的让我想起计算机二进制里面的1和0,哈哈。
通常这个数据类型是用来对程序流程进行控制的,如果你还记得判断语句,就会发现一个判断语句可以执行下去的依据就是布尔值,如下:
// 无限循环
所以在JavaScript预期是布尔值的地方(如if后面的括号里面),就会根据各种条件运算出对应的布尔值,包括:
- 前置逻辑运算符: ! (Not)
- 相等运算符:==,===,!=,!==
- 比较运算符:>,>=,<,<=
通过上面的这些运算符,就可以得到布尔值了;不过也有可能看到一种很特殊的情况,就是括号里面是一个非布尔值的变量,这种情况下,由于JavaScript预期会得到布尔值,就会进行强制的自动类型转换,把下面这6个值识别为false:
- undefined
- null
- false
- 0
- NaN
- ""或''(空字符串)
而除此以外的其他值自动识别为true。
如图,空字符串为false:
在这个地方经常会有个误解,因为空字符串会被认为是伪,有些人会感觉空数组或者空对象应该也是伪,可事实上呢?
其实空数组或者空对象在自动转换的时候,会被识别为真(true)的,注意别踩这个坑!
2. 数值
2.1 整数和浮点数
和其他的语言有很大的区别,JavaScript是没有区分整数和浮点数的,在它内部,所有的数值都是使用64位的浮点数储存的,故而请注意1和1.0是全等的:
类似的运算在Python当中虽然也可以得到相同的结果,因为Python会自动将整数值转换为浮点数进行对比计算,但是两者并不全等,所以使用1 is 1.00 进行判断得到的结果是False(Python当中的布尔值首字母是大写的):
也就是说,JavaScript底层根本没有整数这个类型,所有的数字类型其实都是浮点数值。由于浮点数设计之初就不是个精确的数值,故而一定要留意带有小数点的浮点数相互计算的结果,譬如下面的这个经典问题:
别怀疑自己的眼睛,事实如此,我也很无奈……
2.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...xxx的形式,其中xx...xxx的部分保存在64位浮点数之中,最长可能为52位。因此,JavaScript 提供的有效数字最长为53个二进制位。
(
上面公式是正常情况下(指数部分在0到2047之间),一个数在 JavaScript 内部实际的表示形式。
精度最多只能到53个二进制位,这意味着,绝对值小于2的53次方的整数,即
如上图第一到第三行,在
如上图,超出的几位数字,是完全无法保存的……
2.3 数值范围
根据标准,64位浮点数的指数部分的长度是11个二进制位,意味着指数部分的最大值是2047(2的11次方减1)。也就是说,64位浮点数的指数部分的值最大为2047,分出一半表示负数,则 JavaScript 能够表示的数值范围为
如果一个数大于等于2的1024次方,那么就会发生“正向溢出”,即 JavaScript 无法表示这么大的数,这时就会返回Infinity;而如果一个数小于等于2的-1075次方(指数部分最小值-1023,再加上小数部分的52位),那么就会发生为“负向溢出”,即 JavaScript 无法表示这么小的数,这时会直接返回0。
来看个实际的例子,我们声明名字为x变量,赋值为0.8,通过循环让它连续自乘25次:
由于最后结果太接近0,超出了可表示的范围,JavaScript 就直接将其转为0。
JavaScript 提供Number对象的MAX_VALUE和MIN_VALUE属性,返回可以表示的具体的最大值和最小值。
2.4 数值的进制和表示方式
JavaScript 对整数提供四种进制的表示方法:十进制、十六进制、八进制、二进制。
- 十进制:没有前导0的数值。
- 八进制:有前缀0o或0O的数值。
- 十六进制:有前缀0x或0X的数值。
- 二进制:有前缀0b或0B的数值。
默认情况下,JavaScript 内部会自动将八进制、十六进制、二进制转为十进制,比如:
如果在这些进制的数值当中出现不正确的其他数值,就会报错。
- 八进制数值不能包含数字8和9;
- 十六进制数值不能包含排序在F(代表15)之后所有字母;
- 二进制数值不能包含大于1的数字;
如下图:
以上这些都是用字面形式直接表示,JavaScript也可以支持使用科学计数法表示:
科学计数法允许字母e或E的后面,跟着一个整数,表示这个数值的指数部分。
以下两种情况,JavaScript 会自动将数值转为科学计数法表示,其他情况都采用字面形式直接表示。
- 小数点前的数字多于21位;
- 小数点后的零多于5个;
如图:
2.5 几个特殊数值
- 0
JavaScript 的64位浮点数之中,有一个二进制位是符号位。这意味着,任何一个数都有一个对应的负值,就连0也不例外。
JavaScript 内部实际上存在2个0:一个是+0,一个是-0,区别就是64位浮点数表示法的符号位不同,本质上来说它们是等价的。
仅有一种特殊的情况,两者会不同:
这是因为前者得到的结果是正无穷大(+Infinity),而后者是负无穷大(-Infinity),故而两者不全等。
- Infinity
无穷大,即Infinity,用来表示两种场景。一种是一个正的数值太大,或一个负的数值太小,无法表示;另一种是非0数值除以0,所得到的结果(是的,开发编程的世界里,0有的时候也可能是分母)。
上图中0除以0得到的是NaN(即非数值,Not a Number)。
Infinity有正负之分,即正无穷大和负无穷大,分别代表大于一切数值和小于一切数值(不包括NaN),且两者并不相等:
Infinity的计算规则就是典型的数学意义上的运算规则:
-
- 任何非0非NaN且非无穷数值与之相加、相减、相乘,结果都是无穷(区分符号);
- 任何非0非NaN且非无穷数值除以无穷,结果都是0;反之则是无穷;
- 0乘以无穷,结果为NaN;其他运算则同上;
- 无穷减去或是除以无穷,结果为NaN;
- null在计算中会被转换为0,等同于0与无穷的计算规则;
- undefined与无穷计算,结果都为NaN;
如下各图:
- NaN
上面频繁的看到这个奇怪的数值NaN,它是JavaScript 的特殊值,表示“非数字”(Not a Number),主要出现在将字符串解析成数字出错的场合,以及一些数学运算会出现错误的场合,尤其是0 / 0:
NaN不等于任何数值,包括它本身,这也就意味着无法通过比较运算符来判断NaN:
与任何数值的计算结果,都是NaN:
由于数值正向溢出(overflow)、负向溢出(underflow)和被0除,JavaScript 都不报错,所以单纯的数学运算几乎没有可能抛出错误。
3. 数值相关的全局方法
3.1 parseInt()
parseInt()这个方法,主要是用于将字符串转换为整数,直接把需要转换的字符串(变量)作为方法的参数放入括号内即可:
parseInt
内部处理方式:
- 当字符串头部有空格的时候,会自动去除:
- 如果待转换对象不是字符串,则会先转换为字符串,再转换为整数:
- 在转换过程中,会按照字符串的字符顺序依次转换,一旦遇到无法转换为数字的字符,就会停止转换进程,直接返回已转换的所有数字:
- 如果第一个就是无法转换的字符,则不进行任何转换动作,并返回NaN:
- 该方法只会按照十进制进行转换,遇到0x开头的十六进制数字,也会转换为十进制整数:
- 对于所有以科学记数法表现的数值,或者会被自动转换为科学记数法的数值,该方法无法转换,并会出现奇怪的错误:
- 该方法可以接受第二个参数,将其他进制的整数转换为十进制数值,但该参数只接受2-36之间的数值,超过该范围,结果为NaN:
- 如果第二个参数是0、null以及undefined,则会直接忽略,使用默认的10作为参数:
使用该方法,最需要注意的,就是自动类型转换所造成的各种意料之外的结果。
3.2 parseFloat()
有了转换整数的方法,自然会有转换浮点数的方法,就是这个parseFloat()了。
parseFloat
内部处理方式:
- 对字符串的处理和parseInt()一致:去除头部空格、先转换为字符串再转换为浮点数值、依照字符串字符次序处理等:
- 会将空字符串处理为NaN:
- 如果字符串符合科学计数法,则会进行相应的转换:
3.3 isNaN()
该方法本意是用来对非数值NaN进行判断,但由于设计上会对类型进行自动转换,字符串在转换后也会变成NaN,故而有可能需要判断的变量是字符串而不是原始的NaN:
同理,数组和对象的判断结果也会是true;不过空数组或只包含一个数值成员的数组,则会转换为数值从而结果为false:
故而为了避免得到不想要的结果,最好先判断一下变量的基础类型。
建议一个更可靠的方法:利用NaN为唯一不等于自身的值的这个特点,进行判断。
function
3.4 isFinite()
该方法返回一个布尔值,表示某个值是否为正常的数值。
除了Infinity、-Infinity、NaN和undefined这几个值,isFinite()对于其他的数值都会返回true。