JavaSrcipt的数字(number):深入理解内部机制
一、数字的语法
JavaScript中的数字字面量一般用十进制表示。在JavaScript中表示数字的数据类型只有一种Number,这种天使与魔鬼同体的数据类型也就只有js了。
//同时表达整数和浮点数
var a = 78,
b = 78.3;
console.log(typeof a);//number
console.log(typeof b);//number
然后还有一些奇葩的数字表示法:
var a = 0.42,
b = .42;
if(a === b){
console.log("你讲得对。")
}
一般情况下,奇葩都是成双成对的:
var a = 69.0,
b = 69.;
if(a === b){
console.log("你讲得对。")
}
这种奇葩你认识它就好了,最好不要出现在你的代码里,记得这种长得丑的写法不报错,但也没事别给自己挖坑。
var a = 89.900,
b = 98.0;
console.log(a);//89.9
console.log(b);//
小数点后面最后的面的零不管几个都省略,有时候发点神经,不拖泥带水还是挺潇洒的。然后还有指数计数格式计数与指数显示。
var a = 9E10;
console.log(a);//90000000000--通常我们使用指数计数法但是不会按照指数计数法显示
console.log(a.toExponential());//9e+10--通过toExponential方法转换成指数计数法字符串形式显示
var b = a * a;
console.log(b);//8.1e+21--当数字长度超出一定范围就会自动转成指数计数法
var c = 1 / b;
console.log(c);//1.234567901234568e-22--小写范围超出也会被转成指数计数法
这时候就有一个尴尬的问题来了,显示的是指数计数字面量,有多少人认识呢?所以就需要做数字化字面量处理:(下面的解决方案只能解决JavaScript整数安全范围内和最小小数范围内的数值。超出这个范围的数值听说可以解除Math.js,我也是在别人的博客里看到有介绍过的,没有亲测过。)
function toNonExponential(num) {
var m = num.toExponential().match(/\d(?:\.(\d*))?e([+-]\d+)/);
//通过match检索每个整个分组的值(非抓捕除外),并以数组表示
//(m[1] || '').length;//--\d*--获取到小数位的长度
//m[2];//--([+-]\d+)--获取到指数
//(m[1] || '').length - m[2];小数位长度与指数的查(小数的长度)
//小数位长度为负数时,设置为0--math.max取最大值
return num.toFixed(Math.max(0, (m[1] || '').length - m[2]));
}
toNonExponential(3.3e-7) // "0.00000033"
toNonExponential(3e-7) // "0.0000003"
toNonExponential(1.401e10) // "14010000000"
toNonExponential(0.0004) // "0.0004"
指定小数部分的显示数位:Number.toFixed(x)
var a = 878.59;
a.toFixed(0);//"879"
a.toFixed(1);//"878.6"
a.toFixed(2);//"878.88"
a.toFixed(3);//"878.880"
关于toFixed方法会对数值做四舍五入处理,小数位不够时后面自动用0补齐,返回的值是字符串类型,参数x的取值范围是0~20。接下来看看有效数位处理方法toPrecision(x)
var a = 34.29;
a.toPrecision(1);//"3e+1"
a.toPrecision(2);//"34"
a.toPrecision(3);//"34.3"
a.toPrecision(4);//"34.29"
a.toPrecision(5);//"34.290"
//注意报错
34.toPrecision(3)//SyntaxError
34.toFixed(2)//SytaxError
(34).toPrecision(3);//34.0
(34).toFixed(2);//34.00
Number.toPrecision(x)方法也是会进行四舍五入操作,并且在数位无法表达数值的时候回进行科学计数法处理。值得注意的是toFixed(x)和toPrecision(x)这两个方法在遇到整数字面量调用时,需要用小括号将数值包裹起来,不然会报错。
最后就是一些特殊格式的数字字面量:
console.log(0xf3);//243--数字字面量十六进制
console.log(0363);//243--数字字面量八进制
//ES6支持的新格式
console.log(0o363);//243--ES6版本的数字字面量八进制
console.log(0b11110011);//234--ES6版本数字字面量二进制
二、很小的数字与JavaScript的数值精确问题
console.log(0.1 + 0.2 === 0.3);//false
从上面的代码我们可以看到一个违背了数学逻辑的问题,这是为什么呢?因为JavaScript所遵循IEEE754编程语言规范,这不只是JS的问题,而是所有遵循这一规范的编程语言都如此,也是通常说的二进制浮点数的精度缺陷,在这一精度下0.1+0.2的结果是0.30000000000000004,所以条件判断结果为false。
解决这一问题的办法就是设置一个误差范围,也就是通常说的“机器精度”,这个值通常是2^-52(2.220446049250313e-16)。在ES6中该值定义在Number.EPSILON中,在ES6的环境下我们可以直接拿来用,来版本环境可以通过计算获得这个值来使用:
if(!Number.EPSILON){
Number.EPSILON = Math.pow(2,-52);
}
//这时候我们就可以来解决两个数字是否相等的问题了
function numbersCLoseEE(n1,n2){
return Math.abs(n1 - n2) < Number.EPSILON;
}
var a = 0.1 + 0.2;
var b = 0.3;
numbersCLoseEE(a,b);
三、整数(范围、检测、32位有符号整数)
3.1JavaScript中整数最大可呈现2^53 - 1,即9007199254740991,在ES6中被定义为Number.MAX_SAFE_INTEGER。整数最小可呈现-(2^53 - 1),即-9007199254740991,在ES6中定义为Number.MIN_SAFE_INTEGER。超出这个范围的数字就只能采用字符串的方式来呈现了。
3.2关于检测一个数值是否是整数,可以使用ES6中的NumBer.isInteger(..)方法,老版本就只能自己做兼容处理:
Number.isInteger(42); //true
Number.isInteger(42.00); //true
Number.isInteger(42.3); //false
//Number.isInteger(..)的兼容模式
if(!Number.isInteger){
Number.isInteger = function(num){
return typeof num == "number" && num % 1 == 0;
}
}
关于检测一个数值是否是安全整数(即在最大范围和最小范围内的整数),可以使用ES6中的Number.isSafeInteger(...)方法,老版本做兼容处理:
if(!Number.isSafeInteger){
Number.isSafeInteger = function(num){
return Number.isInteger(num) && Math.abs(num) <= Number.MAX_SAFE_INTEGER;
}
}
ES 6 增加了以下三个 Number 对象的属性:
- EPSILON: 表示 1 和比最接近 1 且大于 1 的最小 Number 之间的差别
- MIN_SAFE_INTEGER: 表示在 JavaScript中最小的安全的 integer 型数字 (
-(253 - 1)
)。 - MAX_SAFE_INTEGER: 表示在 JavaScript 中最大的安全整数(
253 - 1
)。
3.3JavaScript32位有符号整数:
虽然最大整数能够达到53位,但是有些数字操作只适应于32位数字,所以这些操作的数字范围只能在Math.pow(-2,31)到Math.pow(2,31)。
或运算符(“|”)只适应于32位以内的整数运算,所以有任意大小整数通过或运算符运算的话没有意义,比如任意大小整数a与0的运算,(a | 0)从运算范围来理解,这个运算本质上不存在任何意义。
四、特殊数字
1.不是数字的数字(NaN)
数学运算时,操作数不是数字类型或者无法解析为常规的十进制或十六进制数字,就无法返回有效的数字,这种情况就会返回NaN。
var a = 2 / "foo"; //NaN
typeof a === "number"; //true
作为一个不是数字的Number类型的值,有一个特性是它不等于任何值,包括他自己(这家伙傻的可爱)。
var a = 2 / "foo";
a == NaN; //false
a === NaN; //false
//而且它很确定自己就不是自己
NaN != NaN; // true
既然无法进行比较,那如果在程序中我们由不得不比较它呢?全局对象window上有一个方法isNaN(...)可以用来判断它!
var a = 2 / "fuh";
window.isNaN(a);//true
但是,全局对象上的isNaN(...)并不靠谱,这个方法在检测值的时候,只要被判断的值不是数字就返回true。
var a = "aaa";
console.log(window.isNaN(a));//true
然后ES6在Number对象上添加了isNaN的方法解决了这个问题,但是老版本的浏览器就得要做兼容处理了:
if(!Number.isNaN){
Number.isNaN = function(n){
return (
typeof n === "number" &&
window.isNaN(n)
);
};
}
var a = 2 / "abc";
var b = "abc";
console.log(Number.isNaN(a));//true
console.log(Number.isNaN(b));//false
这个兼容的写法有点累赘,其实还有一个更简单的写法:
if(!Number.isNaN){
Number.isNaN = function(n){
return n !== n;
}
}
2.无穷数
在JavaScript中除数是可以为0的,当1除以0时结果为Infinity(即Number.POSITIVE_INFINITY)。无穷数在JavaScript中也存在正无穷和负无穷,当一个负数除以0时,就可以得到-Infinity。
var a = 1 / 0;//Infinity
var a = -1 / 0;//-Infinity
因为JavaScript遵循IEEE754规范,在断定断定无穷数时存在向上和向下取值行为,我们知道在JavaScript中定义了最大值属性(Number.MAX_VALUE);但这个最大值并不代表再加上一个数就是无穷了,而且这个数跟一的差距还特别大,这种界定无穷的方法通俗来讲就是这个介于最大值和无穷之间的数更接近那一边。
console.log(Number.MAX_VALUE);//1.7976931348623157e+308
var a = Number.MAX_VALUE;
a + a; // Infinity
a + Math.pow(2,970);// Infinity
a + Math.pow(2,969);// 1.7976931348623157e+308
//这部分不太必要过多研究,可能在你的工作中永远不会用到这个知识点,有兴趣的话作为学术讨论就好
要注意一点的是无穷除以无穷的结果为NaN。
3.零值
在JavaSrcipt中零是存在正负值的特殊数值,当零除以负数时得到的就是一个(-0),当然一个负数乘以零也是得到(-0);
var a = 0 / -5;//-0
var b = 0 * -6;//-0
在控制台打印时,这个结果并不一定准确,会因不同的浏览器和版本有不同的情况;还有一个情况就是在零值转换为字符串类型是就不会保留负值这个特性了,但是当带有负号的数字0的字符串转换成数字格式时又会保留负值。
var a = 0 / -9; //-0
a.toString(); //"0"
a + ""; //"0"
String(a); //"0" + "-0"; //-0
Number("-0"); //-0
JSON.parse("-0"); //-0
既然零值存在正负特性,但是在普通的逻辑运算看来0和-0是同一个东西,这两个东西是相等的。那么就会需要有判断正负的机制,写一个判断值为负零(-0)的方法:
function isNegZero(n){
n = Number(n);
return (n === 0) && (1 / n === -Infinity);
}
JavaSrcipt的数字(number):深入理解内部机制的更多相关文章
- 从底层带你理解Python中的一些内部机制
下面博文将带你创建一个字节码级别的追踪API以追踪Python的一些内部机制,比如类似YIELDVALUE.YIELDFROM操作码的实现,推式构造列表(List Comprehensions).生成 ...
- 搭建高可用mongodb集群(三)—— 深入副本集内部机制
在上一篇文章<搭建高可用mongodb集群(二)—— 副本集> 介绍了副本集的配置,这篇文章深入研究一下副本集的内部机制.还是带着副本集的问题来看吧! 副本集故障转移,主节点是如何选举的? ...
- SQL Server 内存中OLTP内部机制概述(二)
----------------------------我是分割线------------------------------- 本文翻译自微软白皮书<SQL Server In-Memory ...
- 搭建高可用mongodb集群(三)—— 深入副本集内部机制
在上一篇文章<搭建高可用mongodb集群(二)-- 副本集> 介绍了副本集的配置,这篇文章深入研究一下副本集的内部机制.还是带着副本集的问题来看吧! 副本集故障转移,主节点是如何选举的? ...
- 并发—JVM内部机制和外部机制处理方法
并发常见的编程场景,一句话概括就是,需要协调多个线程之间的协作,已保证程序按照自己原本的意愿执行.那么究竟应该如何协调多个线程? 这个问题比较宽泛,一般情况下,我们按照方式的纬度去简单区分,有以下两种 ...
- mongodb副本集的内部机制(借鉴lanceyan.com)
针对mongodb的内部机制提出以下几个引导性的问题: 副本集故障转移,主节点是如何选举的?能否手动干涉下架某一台主节点. 官方说副本集数量最好是奇数,为什么? mongodb副本集是如何同步的?如果 ...
- 万字综述,核心开发者全面解读PyTorch内部机制
斯坦福大学博士生与 Facebook 人工智能研究所研究工程师 Edward Z. Yang 是 PyTorch 开源项目的核心开发者之一.他在 5 月 14 日的 PyTorch 纽约聚会上做了一个 ...
- ElasticSearch 文档(document)内部机制详解
1.数据路由 1.1 文档存储怎么路由到相应分片? 一个文档,最终会落在主分片的一个分片上,到底应该在哪一个分片?这就是数据路由. 1.2 路由算法 shard = hash(routing) % n ...
- new和instanceof的内部机制
new和instanceof的内部机制 首先我们来看看obj = new o()这条语句发生了什么: var obj = (function(){ var obj = {}; obj.__proto_ ...
随机推荐
- Android studio 3.1.2报错,no target device found
Android studio 3.1.2的Android monitor改为Android profiler,直接点这个就可以真机调试,在手机安装相应文件 第二次启动时,再次报错,找不到设备,点一下 ...
- Hdoj 1160.FatMouse's Speed 题解
Problem Description FatMouse believes that the fatter a mouse is, the faster it runs. To disprove th ...
- Docker部署Jenkins测试环境
安装docker环境 yum install epel-release -y && yum install docker -y 如果是高手需要docker-compose的话就再装个d ...
- 借网站日记分析~普及一下Pandas基础
对网站日记分析其实比较常见,今天模拟演示一下一些应用场景,也顺便说说Pandas,图示部分也简单分析了下 1.数据清洗¶ 一般数据都不可能直接拿来用的,或多或少都得清理一下,我这边就模拟一下清洗完 ...
- BAT脚本实例
一个简单的BAT脚本实例,重点在于说明各命令用法: @ ECHO OFF REM 打开ECHO回显 echo 1.列出C盘根目录中所有文件 pause dir C:\ echo. echo 2.等待1 ...
- 将Excel导出为SQL语句
需求说明:公司做项目前进行需求分析,确定表结构后需要建表,如果照着表格去敲,那就太麻烦了,所以想到了自动生成SQL语句. 思路大概就是:解析Excel,拼接SQL语句,输出SQL文件. 第三方jar包 ...
- Luogu P2519 [HAOI2011]problem a
题目链接 \(Click\) \(Here\) \(DP\)神题.以后要多学习一个,练一练智商. 关键点在于把"有\(a_i\)个人分数比我高,\(b_i\)个人分数比我低"这句话 ...
- Mac 软件专题:高效率工作和学习工具软件推荐
今天和大家分享软件专题:「高效率工作和学习工具」,简而言之就是提高你工作和学习效率的软件,这对于要天天使用Mac工作或学习的人来说太有帮助了,这里主要分享大家平时经常用的一些,欢迎留言补充. 本文图片 ...
- go config
安装导入 go get github.com/astaxie/beego/config import "github.com/astaxie/beego/config" 使用 配置 ...
- 剑指Offer_编程题_10
题目描述 我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形.请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法? class Solution { public: int r ...