JS红宝书学习-第3章 语言基础 --数据类型_Number
3.4 数据类型
1.Number类型
ES中Number类型使用的是IEEE754格式表示整数和浮点数,不同数值类型相应地也有不同的数值字面量格式
基本的数值字面量格式是十进制整数,直接写出来即可:
let intNum = 55; // 整数
整数也可以使用八进制或十六进制字面量表示。对于八进制字面量,第一个数字必须是零(0),然后是相应的八进制数字(数值0~7)。如果包含的数字超出了应有的范围,就会忽略前缀的零,后面数字序列被当成十进制。
let octalNum1 = 070; // 八进制的56
let octalNum2 = 079; // 无效的八进制,忽略前缀变为79
let octalNum3 = 08; // 无效的八进制忽略前缀变为8
八进制的字面量在严格模式下是无效的,会抛出语法错误。在es6中八进制可以用前缀0o来达字面量。
对于十六进制字面量,必须以0x作为数值前缀,然后是16进制数字(09以及AF)。十六进制数字中的字母大小写均可。
let hexNum1 = 0xA; // 十六进制10
let hexNum2 = 0x1f; // 十六进制31
使用八进制与十六进制核实创建的数值在所有数学操作中都被视为十进制数值。
js中存在正零(+0)和负零(-0)。它俩在任何场景都被被认为是相同的。
1.1 浮点值
要定义浮点数必须包含小数点,且小数点后至少有一个数字。虽然小数点前面不是必须有整数,但是推荐加上。
let floatNum1 = 1.1;
let floatNum2 = 0.1;
let floatNum3 =.1; // 这个也有效,但是不推荐
因为浮点数使用的内存是整数的两倍,所以es总会把值转换为整数。在小数点后面没有数字的情况下会直接转换为整数,同样如果数值本身是整数,只是小数点后面跟了一个0,name也会转换为整数。
let floatNum1 = 1.; // 小数点后面没数字,当成整数1处理
let floatNum2 = 1.0; // 小数点后面是0,当成整数1处理。
对于非常大或者非常小的数值,浮点值可以用科学计数法来表示。科学记数法用于用于表示一个应该乘以10的给定次幂的数值。es中的科学记数法的格式是要求一个数值(整数或者浮点数)后面跟一个大写或者小写的e,在加上一个要乘10的多少次幂。
let floatNum = 3.3333e4; // 等于33333
虽然我们也可以直接写上floatNum的值为33333,但是这样会更加的简洁准确。
科学记数法也可以用作表达非常小的数值,例如:
let floatNum = 3e-6; // 0.000003
默认情况下,es会将小数点至少包含6个零的浮点值转换为科学记数法。(这个地方很有趣,我在之前做练习的时候在控制台输入3e-16一直返回3e-16,我还以为我写错了,看完才明白。。。)
浮点值得精准度最高可达17位小数,但是算数计算中远不如整数精确。例如,0.1+0.2得到的就不是0.3,而是0.30000000000000004。由于这种微小的舍入错误,导致很难测定特定的浮点值,但是你说气不气有些值它好用,计算正确。所以以防万一,不要测试某个特定的浮点值。
let a = 0.1, b = 0.2, c = 0.3;
if(a + b == c){ // 你说奇不奇怪
console.log("我是你得不到的0.3");
}
if(a + c == 0.4){ // 我又好使了
console.log("为啥上面的兄弟不好使");
}
注意之所以存在这种舍入锁雾,是因为使用了IEEE754数值,其余使用相同格式的也有这个问题。(这个问题我看到很多不同文章来说明原因,大体是计算机计算数值的原因,当我们需要精度高的浮点数可以使用BigNumber来确保准确~~~)
1.2 值的范围
由于内存限制,es并不支持世界上的所有数值,es可以表示的最小数值保存在Number.MIN_VALUE中,大多浏览器为5e-324;如果某个计算得到数值超出了js的表示范围,那么就会被转换为一个特殊的Infinity(无穷)值。任何无法表示的附属以-Infinity表示,正数以Infinity表示。
如果计算返回正Infinity或-Infinity,则该值不能再进一步用于任何计算。这是因为Infinity没有可用于计算的数值表示形式。可以使用isFinit()函数来判断值是否为有限性的值。
let result = Number.MAX_VALUE 1;
console.log(isFinite(result)); // false
1.3 NaN
在Number中有一个特殊的值NaN,意思是”不是数值“,用于表示本来要返回数值的操作失败了,比如,用0除任意数值的其他语言通常都会导致错误,从而结束代码执行,但是ES中,0,+0,-0相处都会返回NaN。
conosle.log(0/0); // NaN
如果分子是非0值,分母是有符号的0,+0,-0,则会返回Infintiy或-Infinity;
console.log(5/0); // Infinity
console.log(5/-0); // Infinity
NaN有几个特殊的属性。首先,任何涉及NaN的操作始终返回NaN。其次,NaN不等于包括与NaN在内的任何值。
console.log(NaN == NaN); // false
为此,ES提供了isNaN()函数。该函数接受一个参数,可以是任意数据类型,然后判断这个参数是否为”不是数值“。把一个值传给isNaN()后,该函数会尝试把它转换为数值,某些非数值的值可以直接转换成数值,如字符串”1“或者布尔值,任何不能转换为数值的值都会返回true。
console.log(isNaN(NaN)); // true
console.log(isNaN(10)); // false,10 是数值
console.log(isNaN("10")); // false,可以转换为数值 10
console.log(isNaN("blue")); // true,不可以转换为数值
console.log(isNaN(true)); // false,可以转换为数值 1
注意:isNaN()可以用来测试对象,此时,首先会调用对象的valueOf()方法,然后再确定返回的值时候可以转换为数值。如果不能,在调用toString()方法,并测试其返回值。这个我也不太懂,我往后看看,再补充~~
1.4 数值转换
终于到了这个地方,我们在开发中关于数值方面出的bug一般从此处出现。。。
有三个函数可以将非数值转换为数值:Number(),parseInt()和parseFloat()。
Number()是转型函数,可以用于任何数据类型。parseInt()和parseFloat()函数主要用于将字符串转换为数值。对于同样的参数,这三个函数执行的操作也不同。
Number()函数基于如下规则执行转换。
| 类型 | 值 | 转换结果 |
|---|---|---|
| Boolean | true | 1 |
| Boolean | false | 0 |
| Number | Number | 直接返回 |
| Null | null | 0 |
| Undefined | undefined | NaN |
| String | 字符串包含数字或者、包括数值字符前包含+/-号则转换一个十进制数值 | 返回或略前面0的数值 |
| String | 字符串有效的浮点值格式,如1.1 | 返回同样的1.1,(同样有0忽略0) |
| String | 字符串包含有效的十六进制格式 | 会返回转换为十六进制对应的十进制数值 |
| String | 如果字符串包含除上述情况之外的其他字符、 | NaN |
| 对象,调用valueOf()方法,并按照上述转换返回值,如果返回NaN,则调用toString()方法,再按照转换字符串的规则转换。 |
从不同数据类型到数值的转换有时候比较复杂~,多看看上面的转换规则。
考虑到用Number()函数转换字符串时相对负责且有点反常规,通常在需要得到整数的时候可以优先使用parseInt()函数。parseInt()函数更专注于字符串是否包含数值。字符串最前面的空格会被忽略,
如果第一个字符时 不是数值字符 或 +/-符号,会立即返回NaN。这意味这空字符也会返回NaN。
如果第一个字符是数值字符,+/-则继续一次检查每个字符直到字符末尾,或碰到非数值字符。如:”12哈哈哈“会被转换为12,因为”哈哈哈“会被忽略,类似”12.5“也是会被转换为12,因为小数点不是有效整数字符。
假设字符串中第一个字符是数值字符,parseInt()函数也能识别不同的整数格式(十进制,八进制,十六进制)。也就是字符串以”0x“开头,就会被解释为十六进制,如果字符串以"0"开头且紧跟数值(不好使~)在非严格模式下会被解释为八进制整数。
let num1 = parseInt(""); // NaN
let num2 = parseInt("0xA"); // 10,十六进制
let num3 = parseInt(015); // 13,八进制
let num4 = parseInt("70"); // 70,十进制
不同的数值很容易混淆,因此parseInt()函数也接受第二个参数,用于指定底数(进制)。如果知道要解析的是十六进制,那么可以传入16作为第二个参数,以便解析。
let num = parseInt("0xAF",16); // 175
事实上,如果提供了十六进制参数,那么字符串前面的"0x"可以省掉。
let num1 = parseInt("AF",16); // 175
let num2 = parseInt("AF"); // NaN
通过第二个参数,可以极大扩展转换后护额的的结果类型。比如
let num1 = parseInt("10", 2); // 2,按二进制解析
let num2 = parseInt("10", 8); // 8,按八进制解析
let num3 = parseInt("10", 10); // 10,按十进制解析
let num4 = parseInt("10", 16); // 16,按十六进制解析
建议,如果有类型转换时,不可预测时,传入底数进行控制。
parseFloat()函数的工作方式跟 parseInt()函数类似,都是从位置 0 开始检测每个字符。同样,
它也是解析到字符串末尾或者解析到一个无效的浮点数值字符为止。这意味着第一次出现的小数点是有
效的,但第二次出现的小数点就无效了,此时字符串的剩余字符都会被忽略。因此,"22.34.5"将转换
成 22.34。
parseFloat()函数与另一个不同之处在于,它始终忽略字符串开头的零。这个函数能识别前面讨论的所有浮点格式,以及十进制格式,parseFloat()函数只解析十进制数据,也不能指定底数,十六进制数据始终返回0。如果字符串表示整数(没有小数点或者小数点后面只有一个0),则parseFloat()返回整数。
let num1 = parseFloat("1234blue"); // 1234,按整数解析
let num2 = parseFloat("0xA"); // 0
let num3 = parseFloat("22.5"); // 22.5
let num4 = parseFloat("22.34.5"); // 22.34
let num5 = parseFloat("0908.5"); // 908.5
let num6 = parseFloat("3.125e7"); // 31250000
let num7 = parseFloat(0xA); // 10,这样可以
let num7 = parseFloat(015); // 13, 这个也可以
公司换新领导,外包公司,两个现场疯狂切换最近没有更新,我这么菜还被人嫉妒~,救救我啊,不想管这么多,这么穷还内斗啥,安心写玩代码不好么。
加油

浙公网安备 33010602011771号