语法》第三章 数值
(本文为阮一峰js标准教程的学习笔记,旨在总结该教程中涉及的知识点大纲及个人所做的一些拓展,方便作为“目录”或者“大纲”复习和查漏补缺,详细内容请参见阮一峰教程原文)
第二部分 语法
**********第三章 数值***************
一.概述
1.所有数都是以64位浮点数形式储存的。1与1.0相同(8bit、也就是64位二进制数)
2、JavaScript 语言的底层根本没有整数,所有数字都是小数(64位浮点数)。
3、由于浮点数不是精确的值,所以涉及小数的比较和运算要特别小心。
0.1 + 0.2 === 0.3
// false
0.3 / 0.1
// 2.9999999999999996
(0.3 - 0.2) === (0.2 - 0.1)
// false
4、容易造成混淆的是,某些运算只有整数才能完成,此时 JavaScript 会自动把64位浮点数,转成32位整数,然后再进行运算,参见《运算符》一节的”位运算“部分。
二、数值精度
1、国标IEEE754,JavaScript 浮点数的64个二进制位,从最左边开始,是这样组成的。
第1位:符号位,0表示正数,1表示负数
第2位到第12位:指数部分
第13位到第64位:小数部分(即有效数字)
IEEE 754 规定,有效数字第一位默认总是1,不保存在64位浮点数之中。因此,JavaScript 提供的有效数字最长为53个二进制位。
2.精度最多只能到53个二进制位,这意味着,绝对值小于2的53次方的整数,即-(2的53次方-1)到2的53次方-1,都可以精确表示。【内部细节不详】
Math.pow(2, 53)
// 9007199254740992
Math.pow(2, 53) + 1
// 9007199254740992
Math.pow(2, 53) + 2
// 9007199254740994
Math.pow(2, 53) + 3
// 9007199254740996
Math.pow(2, 53) + 4
// 9007199254740996
Math.pow(2, 53)
// 9007199254740992
// 多出的三个有效数字,将无法保存
9007199254740992111
// 9007199254740992000
三.数值范围
1.64位浮点数的指数部分的长度是11个二进制位,意味着指数部分的最大值是2047(2的11次方减1)。
分出一半表示负数,则 JavaScript 能够表示的数值范围为21024到2-1023(开区间),超出这个范围的数无法表示。
2.指数部分等于或超过最大正值1024,JavaScript 会返回Infinity “正向溢出”;
3.指数等于或超过最小负值-1023(即非常接近0),JavaScript 会直接把这个数转为0,“负向溢出”。
var x = 0.5;
for(var i = 0; i < 25; i++) {
x = x * x;
}
x // 0
4.js能表示的最大值和最小值,JavaScript 提供Number对象的MAX_VALUE和MIN_VALUE属性表示。
Number.MAX_VALUE // 1.7976931348623157e+308
Number.MIN_VALUE // 5e-324
四、数值的表示法
1、使用字面量表示 比如: 0xFF(十六进制)
2、科学计数法,允许字符e或E后跟一个整数,表示*10的多少次方。
3、js自动将数值转科学技术法的几种情况(其他均用字面量形式表示)
(1)小数点前的数字多于21位。
1234567890123456789012
// 1.2345678901234568e+21
123456789012345678901
// 123456789012345680000
(2)小数点后的零多于5个。
// 小数点后紧跟5个以上的零,
// 就自动转为科学计数法
0.0000003 // 3e-7
// 否则,就保持原来的字面形式
0.000003 // 0.000003
五、数值的进制
1.使用字面量时,js对整数提供四种进制。
十进制 没有前导0
十六 前导0x或0X
八 0o 或者0O
二 0b 或者0B
2. 特殊:单独的前导0--前导0表示八进制,处理时很容易造成混乱。ES5的严格模式和ES6,已经废除了这种表示法,但是浏览器目前还支持。
通常来说,有前导0的数值会被视为八进制,但是如果前导0后面有数字8和9,则该数值被视为十进制。
0888 // 888 十进制
0777 // 511 被认为是八进制
3.默认js将十六、八、二自动转十(js依赖先导辨认)
4.前导标明进制,又出现不属于该进制数字报错。
六、特殊数值
1、正零和负零
1.1js内部有两个0,+0和-0是等价的/
1.2严格相等+0===-0 +0 -0 0
1.3js中任何一个数都有负值,0不例外;【不讨论NaN】
1.4唯一区别场合:+0和-0当作分母,返回值不相等;
(1/+0)===(1/-0) //false;
原因:一个得到+Infinity 另一个-Infinity
2.NaN
2.1含义:表示非数字
2.2主要出现场景:将字符串转为数字;
2.3一些函数运算结果出现NaN
Math.acos(2) // NaN
Math.log(-1) // NaN
Math.sqrt(-1) // NaN
2.4
0 / 0 // NaN
2.5,NaN不是一种独立的数据类型,而是一种特殊数值,它的数据类型依然属于Number,使用typeof运算符可以看得很清楚。
typeof NaN // 'number'
2.6运算规则:
*不等于任何值,包括自身NaN === NaN // false
*由于数组的indexOf方法,内部使用的是严格相等运算符,所以该方法对NaN不成立。
[NaN].indexOf(NaN) // -1
*Boolean(NaN) // 转布尔false
*与任何数包括自己运算都是NaN
*
2.7 判断NaN方法
2.7.1 isNaN方法:遇到NaN或者可以被转成NaN的值返回true;
*只对数有效,传入其他值自动转。
*传入字符串也会为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
但是,对于空数组和只有一个数值成2.72员的数组,isNaN返回false。
isNaN([]) // false
isNaN([123]) // false
isNaN(['123']) // false
2.7.2使用isNaN之前,最好判断一下数据类型。
function myIsNaN(value) {
return typeof value === 'number' && isNaN(value);
}
2.7.3判断NaN更可靠的方法是,利用NaN是JavaScript之中唯一不等于自身的值这个特点,进行判断。
function myIsNaN(value) {
return value !== value;
}
3.Infinity
3.1定义:特殊数值 number类型,不独立成数据类型;
3.2表示无穷
3.3场景:
*正的太大
*负的太小
*非0数值除以0,得Infinity
注意:0/0是NaN
3.4正负之分:
+Infinity表示正无穷 -Infinity表示负无穷
3.5Infinity大于一切数,-Infinity小于一切 不考虑NaN
3.6Infinity与NaN比较,怎么比都返回false;
3.7
1/-0 -Infinity
-1/-0 Infinity
-1/0 -Infinity
1/0 Infinity
3.8正负向溢出,被零除,js都不报错,说明单纯数学运算几乎没有可能抛出错误;
3.9Infinity的四则运算符合无穷的运算规则;【这条不严谨,并非完全符合】
3.10 0*Infinity//NaN 【居然不是0! 】
3.11 null与Infinity计算 null转0 等同于与0计算
3.12 undefined与Infinity计算全部返回NaN
3.13Infinity加上或乘以Infinity,返回的还是Infinity。
Infinity + Infinity // Infinity
Infinity * Infinity // Infinity
Infinity减去或除以Infinity,得到NaN。
Infinity - Infinity // NaN
Infinity / Infinity // NaN
3.14isFinite函数
isFinite函数返回一个boolean
检查是不是一个正常的数值,或者能否转化为正常数值,遇到NaN,Infinity返回false;
isFinite(Infinity) // false
isFinite(-1) // true
isFinite(true) // true
isFinite(NaN) // false
七、与数值相关的全局方法
1.parseInt()
1.1 字符串转整数
1.2 转出来的数会有向下取整的效果:原因是认不出小数点。
1.3要求参数是字符串。
1.4相关问题:
1.4.1 字符串头部带空格无影响;【中间、尾部空格未知】
1.4.2 遇到不能转为数字的字符,返回已经转好的;
1.4.3 参数不是字符串,先转字符再转数字,这会导致一些令人意外的结果。
parseInt(0x11, 36) // 43
// 等同于
parseInt(String(0x11), 36)
parseInt('17', 36)
1.4.4 字符串的第一个字符不能转化为数字的情况,返回NaN,但是不包括"-123"这样后面跟着数的正负号
1.4.5 parseInt返回值两种可能: 十进制数 NaN
1.4.6 对于那些会自动转化科学技术的情况,parseInt会将科学技术的表示方法视为字符串,最终导致奇怪结果出现。
parseInt(0.0000008) //等同于parseInt('8e-')//8
1.4.7 涉及进制转换
*parseInt('0x10')字符串是带前导的数,parseInt会按照相应的进制解析(命中字符串前导后,会用十六进制解读字符串,为十六进制数,然后转成十进制数返回)
*parseInt('1000',10)第二参默认是十,以十进制解析字符串,除非命中字符串先导或者手动修改这个第二参
*第二个参数是0、undefined和null,则直接忽略。
parseInt('10', 37) // NaN
parseInt('10', 1) // NaN
parseInt('10', 0) // 10
parseInt('10', null) // 10
parseInt('10', undefined) // 10
*第二参是整数,这个整数只有在2到36之间,才能得到有意义的结果,超出这个范围,则返回NaN。
*第二参不是数,或者是小数会自动转成整数,该作死用法此处不研究
*指定了解析进制,字符串中出现无意义字符,从最高位返回可转数,最高位如果都转不了,返回NaN
*指定第二参,就按照第二参的进制解析字符串;
未指定第二参,字符串中有先导被命中,按照先导的进制解析;
以上两个都没有,默认十进制解析;
parseInt('011',2) 会以二进制处理字符串"011" //得到结果是十进制3
parseInt('011') 不同浏览器不一样,有的能认出先导0,有的认不出来认为是10进制;
*对于八进制的前缀0,加上第一参非字符串转字符串,两个问题在一起就更纠结了
parseInt(011, 2) // NaN
// 等同于
parseInt(String(011), 2)
由于String(011)这一步转为"9",具体过程是识别出其中的先导,以八进制解析数字为十进制数字9,完了转为字符串。
*ES5不再允许将带有前缀0的数字视为八进制数,而是要求忽略这个0。但是,为了保证兼容性,大部分浏览器并没有部署这一条规定。
【
parseFloat认不出前导
parseInt parseFloat前后空格过滤,中间空格算识别不出的字符
parseFloat不认前导,没有第二参数来做进制转换功能
parseInt有设定参数控制解析进制的功能,toString()有指定参数控制输出进制的功能;
】
2.parseFloat方法()
2.1含义:parseFloat方法用于将一个字符串转为浮点数;
2.2遇到不能转为浮点数的字符,则返回已转好的;
2.3自动过滤前导空格,参数字符串首位空格忽略
2.4字符串第一个字符都不能转直接返回NaN
2.5参数不是字符串,先转字符串(自动),再转浮点数
2.6字符串书写符合科学计数法,能被命中(能认得出来),返回的数值会做相应转换。
parseFloat('314e-2') //3.14
2.7 parseFloat解析过程中遇到首位(+、-),数字0-9,小数点,科学计数法中的指数标记(e或者E)以外字符,就认不出来了
2.8parseFloat()方法对比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