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_ ...
随机推荐
- 【XSY1081】随机存储器 网络流
题目描述 Bob有\(2^n\)字节的内存,编号为\([0,2^n-1)\).他想对每个字节的内存分别分配一个值.对于编号为\(i\)的内存,如果它被分配了一个值\(j(0\leq j<2^m) ...
- Android assets的一个bug
摘要 Android assets目录下资源文件超过1MB的问题. 由于要显示一些奇奇怪怪的日文字符,我们在应用里放了一个字库文件,譬如叫做jp.ttf,放在assets目录下打包. 开发.调试一切正 ...
- django 模板语言
母版与继承: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UT ...
- centos7安装mha4mysql
mysql搭建mha需要用的两个rpm包.(manager包和node包) 下载地址:https://download.csdn.net/download/dajdajdajdaj/10603389 ...
- python学习day6 数据类型Ⅳ(集合)
day6 数据类型-集合 内容补充: 列表功能: .reverse()反转 v = [1,2,3,4,5,6]v.reverse()print() #[6, 5, 4, 3, 2, 1] .sort( ...
- QML学习笔记(一)-防止鼠标穿透事件
作者: 狐狸家的鱼 Github: 八至 1.防止鼠标穿透 MouseArea{ anchors.fill: parent; onClicked: {}; onReleased: {}; onPres ...
- 如何使用Senparc.Weixin SDK 底层的Redis缓存并设置过期时间
最近在微信第三方平台项目开发中,有一个需求,所有绑定的公众号的回复规则按照主公众号的关键词配置来处理,我的处理思路是获取主公众号配置的关键词回复规则,缓存10分钟,由于需要使用Redis缓存来存储一些 ...
- Vue+koa2开发一款全栈小程序(1.课程介绍+2.ES6入门)
1.课程介绍 1.课程概述 1.做什么? Vue+koa2开发一款全栈小程序 2.哪些功能? 个人中心.图书列表.图书详情.图书评论.个人评论列表 3.技术栈 小程序.Vue.js.koa2.koa- ...
- Vue学习(4)
昨天内容回顾 1.{{}}模板语法.插值.简单运算2.指令系统 v-if 真正销毁重建 v-show 更改css的display,用于重复切换出现 v-bind 绑定属性 : v-on 绑定事件 @ ...
- Day28--Python--网络通信协议 tcp与udp下的socket
昨日内容回顾: 1. CS架构 服务端客户端架构 软件CS架构: 京东,淘宝,QQ,微信,暴风影音,快播 硬件CS架构: 打印机 服务端: 提供服务的 客户端: 享受服务的 BS架构: 浏览器和服务端 ...