1. 存储。
javaScript中的number是使用IEEE 754 标准中的 双精度浮点数。
2. Number
Number是一个原始包装对象,用于表示和操作数字。new Number()使Number变为一个构造器,包含了与数字打交道的常量和方法。函数是对象的子对象,所谓他能够添加属性和方法。称为Number的静态属性和静态方法。当Number不与new一起用,他可以用来进行强制转换(显示强制转换, 是通过调用底层的ToNumber来转换的)。
Number() | 转换为 |
数字 | 字面量转化 |
空字符串 | 0 |
不为空的字符串 | NaN |
布尔值 | 0/1 |
空数组 | 0 |
[1,2,3] | NaN |
对象 | NaN |
函数 | NaN |
NaN | NaN |
undefined | NaN |
null | 0 |
Infinity | Infinity |
具体转换规则是 调用内置的ToNumber方法。
参数是对象的话,会调用ToPretivict(), 因为当前是调用带有 number 的上下文, 会调用对象的toString 和 valueOf 方法。 返回一个基本数据类型。 在进行ToNumber() 转换。
3. Number 的静态属性
-
Number.NaN
它是指一个不是数字的数字。我们理解为一个错误的数字更比较符合,当我们做数学操作,当我们操作失败,程序就会停止执行,我们不像让程序终端,得到了一个错误的数字名叫NaN。window.NaN 和 Number.NaN 是同一个东西,window.NaN != Number.NaN; 这是NaN的一个特性 自己不等于自己。并且所有关于NaN的操作都会得到NaN;
NaN 虽然不是数字 typeof NaN; // number; NaN 是javaScript中唯一一个不等于自己, 也不等于其他任何的值。 NaN == NaN; // false NaN === NaN; // false NaN 是一个Falsy值 Boolean(NaN); // false NaN 与任何的其他数学操作都是NaN NaN + 10; // NaN NaN - 10; // NaN NaN * 10; // NaN; NaN / NaN; // NaN; 在indexOf中, 内部使用的是严格想等。 所以是找不到NaN的。 [NaN].indexOf(NaN); // -1
当数学操作失败或无法返回正确的数值。 就会返回NaN; 5 - 'x'; // 隐式强制转换。 'x' 会被转为一个数字。 Number('x'); --> NaN 5-NaN 0 / 0; // NaN 比较特殊的一个了,在数学中,0 是不能作为除数的,但在js中是返回NaN的。 Math.acos(2); // NaN Math.log(-1); // NaN Math.sqrt(-1); // NaN
这些操作会得到NaN | 得到 |
NaN的其他运算 | NaN |
Number() | NaN |
parseInt() | NaN |
parseFloat() | NaN |
0 / 0 比较特殊 因为 0 做除数本来就是错的 | NaN |
Math中方法的求值 | NaN |
-
Number.MAX_VALUE
Number.MAX_VALUE = 1.7976931348623157e+308
它是指的在number中能表示的最大的数字。它是可以表示的,之所以最大,是因为我们可以表示这个数字,比他大的并且能表示出来的数字是 Infinity。
Number.MAX_VALUE + Number.MAX_VALUE; // Infinity
-
Number.MIN_VALUE
Number.MIN_VALUE = 5e-324
它是指在number中能表示最接近 0 的数字, 它是可以表示的,之所以说是最接近,是因为我们对它的操作会变为 0 , 而不会变为比他小确比0大一点的数字。
Number.MIN_VALUE * 0.1 // 0
-
Number.MAX_SAFE_INTEGER
Number.MAX_SAFE_INTEGER = 9007199254740991; || Number.MAX_SAFE_INTEGER = 2 ** 53 - 1;
它是指number中最大的安全整数。JavaScript使用双精度浮点格式数字,在IEEE 754 只能安全地表示
-(2^53 - 1)
和之间的整数2^53 - 1。不是说你只能写出这么大的整数,比他大但不是
Infinity 的整数也有。请注意看, 我们说的是安全的,除了能够表示整数,还能够正确比较整数的能力。Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2. // true
操作它的整数,比较将与数学是不一致的。
-
Number.MAX_SAFE_INTEGER
它与 Number.MAX_SAFE_INTEGER 的道理是一样的。 只是它代表的是最小表示的安全整数。
Number.MIN_SAFE_INTEGER = Number.MIN_SAFE_INTEGER || Number.MIN_SAFE_INTEGER = -(2** 53 - 1)
-
Number.POSITIVE_INFINITY
它表示 Infinity , 正无穷的值。它的值与全局对象的Infinity属性值相同。
操作 | 得到 |
任何正数 * POSITIVE_INFINITY | POSITIVE_INFINITY |
任何负数 * POSITIVE_INFINITY | NEGATIVE_INFINITY |
0 * POSITIVE_INFINITY | NaN |
NaN * POSITIVE_INFINITY | NaN |
POSITIVE_INFINITY / 负值 | NEGATIVE_INFINITY |
POSITIVE_INFINITY / 正 | POSITIVE_INFINITY |
POSITIVE_INFINITY / NEGATIVE_INFINITY或者POSITIVE_INFINITY | NaN |
任何数字 / POSITIVE_INFINITY | 0 |
-
Number.NEGATIVE_INFINITY
Number.NEGATIVE_INFINITY
属性表示负无穷大。和全局对象的 Infinity 属性的负值相同。
-
Number.EPSILON
Number.EPSILON = Math.pow(2, -52);
它表示一个机器精度。 表示1与可表示出来大于1的最小浮点数之间的差值。
EPSILON 的值接近
2.2204460492503130808472633361816E-16
,或者2-52。
0.1 + 0.2 === 0.3 // false
这是和我们数学上不一样的。因为二进制表示的精度是不准确的。我们会出现一些误差。我们就会得到不是我们想要的结果。也有其他的方法可以解决这个问题。 Number.EPSILON就是其中的一个。因为所造城的误差很小,机器精度足以弥补。
function eps(a, b) { return Math.abs(a - b) < Number.EPSILON; }
3. 静态属性。
-
Number.isNaN
用来测试是否为NaN, 是NaN 就返回true, 否则就返回false。
Number.isNaN = Number.isNaN || function(val) { return typeof val == 'number' && val !== val; // 我们可以利用javascript中所有的类型都等于自己(包括对象的引用),只有NaN 不等于自己。 } Number.isNaN = Number.isNaN || function(val) { val = Number(val); var res = val + '' return res === 'NaN'; }
在全局window.isNaN中, 也可以用来监测是否为NaN, 但是它是会进行一个类型的强制转 换。Number()会把其他类型先转为一个数字,是否被转换为NaN, 是就会返回true。 Number.isNaN 前提是 typeof val == 'number' 首先得是一个数字,不会进行类型强制转换。
Number.isNaN 的参数只能是数字,不会进行强制转换。 isNaN 的参数如果不是数字,会先进行强制转换,是number全局上下文。
-
Number.isFinite
它是用来监测数字是否为一个有限数字。有限数字代表除了 Infinity / -Infinity / NaN , 都为有限的数字。会返回true, 否则为false。
Number.isFinite = Number.isFinite || function(val) { return typeof val == 'number' && isFinite(val); }
全局下的isFinite方法,可以用来监测是否为一个有限数字,会进行Number的类型强制转换。所以其他类型也是可以进行的。
window.isFinite = window.isFinite || function(val) { val = Number(val); var res = val + ''; return res != 'NaN' || val != 'Infinity' || val != '-'Infinity''; }
Number.isFinite 的参数是一个number类型,不会强制转换。isFinite 参数不是number,会先进行一个强制转换,使用的是number全局上下文。
-
Number.isInteger
是否是一个整数, 是就返回true, 否则为false。 不会进行类型强制转换的, 没有全局对应的方法。
Number.isInteger = Number.isInteger || function(val) { return typeof val == 'number' && val % 1 == 0; }; Number.isInteger = Number.isInteger || function(val) { var res = Math.floor(val); return typeof val == 'number' && res == val; }; Number.isInteger = Number.isInteger || function(val) { var res = Math.ceil(val); return typeof val == 'number' && res == val; }; Number.isInteger = Number.isInteger || function(val) { var res = Math.round(val); return typeof val == 'number' && res == val; } Number.isInteger = Number.isInteger || function(val) { var res = parseInt(val, 10); return typeof val == 'number' && res == val; }
Number.isInteget 的参数是 number 类型, 不会进行强制转换。
-
Number.isSafeInteger
是用来监测是否是一个安全整数。是就返回true, 否则就返回false。 不会进行类型转换。没有对应的全局方法。
Number.isSafeInteger = Number.isSafeInteger || function(val) { return Number.isInteger(val) && Math.abs(val) <= Number.MAX_VALUE; }
Number.isSafeInteget 的参数是 number 类型,不会进行强制转换。
-
Number.parseInt
可以用来解析一个字符串。 Number.parseInt = parseInt; 和全局parseInt是一样的。
parseInt(string, radix); 第一个参数是需要解析的字符串。如果不是字符串就会先调用ToString 去转为一个字符串。 它会忽略前后的空格,然后从第一个字符串开始解析,匹配数字字符串,如果第一个字符不是数字,就会返回NaN,然后继续向后解析,匹配到不符就返回匹配到的数字。
ToString 转化 字符串 字符串格式 数字 数字字符串 boolean 对应的布尔值 函数 字符串函数 如果是一个对象的话,会调用内部的ToPretive, 显示的传入 string 的上下文, 然后先调用暴漏出来的 toString, 如果返回的是基本数据类型就返回, 否则就继续调用 valueOf , 如果都没有返回一个基础类型,就报错, 如果返回,就报错。
第二个参数 radix 是一个类型,接受 [2, 36] 之间的数字。如果不是一个数字,就会调用Number() 转换为一个数字。(参见上文中Number的转换)。 如果超过[2, 36]之间的数字,就会报错ranagerError, 它代表的是进制。如果不传入这个参数默认会以 10 进制转换。注意:如果以 0x or 0X 开头的第一个参数会默认为以16进制进行转换。如果第一个字符大于等于radix, 就会得到NaN。 注意: 第二个参数如果不是一个整数,会进行向下取整。
parseInt('123', 10); // 123; parseInt('123', 10.9); // 123;
Number.parseInt = parseInt = Number.parseInt || function(value, radix) { // 超出 radix 范围。 if (radix && (radix < 2 || radix > 35)) return NaN; // 除掉两边的空格 const str = value.toString().trim(); // 匹配16进制 const match16 = str.match(/^(\-|\+)?[0][xX][abcde0-9]+/); if (match16) return Number(match16[0]); // 第一个字符不是数字 const matchResult = str.match(/^(\-|\+)?[0-9]+/); if (!matchResult) return NaN; // 现在我们可以正常处理我们的字符了。 const targetStr = matchResult[0]; // 没有radix进制。 if ( !radix ) { // 我们直接拿10进制来处理。上面已经处理了16进制(不管是默认还是显示的带16)。 return Number(targetStr); } else { //我们得看是否带有符号。 const target = targetStr.match(/^(\-|\+)/); let finalStr = targetStr; let isFlag = false; if (target) { isFlag = target[0] === '-'; finalStr = target.slice(0); } // 第一个字符是否是在范围内。 if (Number(finalStr.slice(0, 1)) >= radix) return NaN; let collectStr = ''; [...finalStr].some(i => { userStr += i; return Number(i) >= radix; }) const targetArray = [...userStr]; // 最重要的,进制转换。 const targetNum = targetArray.reverse().reduce((acc, cur, idx) => { return acc + Number(cur) * Math.pow(radix, idx); }, 0); // 注意,是否带有符号。 return isFlag ? (-0 - targetNum) : targetNum; } }
Number.parseInt 的第一个参数是 string 类型,并且不是string,会发生一个强制转换,带有string的全局上下文。 第二个参数是 number类型,并且不是 number,会强制转换,带有number的全局上下文。
-
Number.parseFloat
可以用来解析一个字符串。 Number.parseFloat = parseFloat; 和全局parseFloat是一样的。
3. 原型上的方法。
我们通过 Number 构造器创建出来的Number,当我们调用它上面的方法的时候,如果它没有,它就会向上层找它的构造函数的原型上的方法。 Number.prototyoe 原型。 然后我们就可以使用了。
-
Number.prototype.toFixed
toFixed 方法使用定点表示法来格式化一个数值。 参数是一个数字,如果不是数字,就会调用 Number() 来进行转换为数字。返回值是一个定长的字符串。如果调用者不是一个数值,就会抛出 TypeError 错误。如果有必要时,会进行四舍五入。如果有必要时,会用 0 来填充小数部分。一个数值的字符串表现形式,不使用指数记数法,而是使用往后面加0来表示。如果数值大于 1e+21, 就会调用 Number.prototype.toString 并返回一个指数记数法格式的字符串。 参数如果不是一个整数,会进行向下取整。
-
Number.prototype.toString
toString 方法返回指定 Number 对象的字符串表示形式。参数是radix, 指定要用于数字到字符串的转换基数 [2, 36]。如果未指定 radix 参数,则默认值为 10。
Number对象覆盖了Object对象上的 toString 方法,它不是继承的 Object.prototype.toString 方法。如果对象是负数,就会保留下符号,(和上文中parseInt的实现一样,会先截取到符号,最后取反而已。
var num = 16; num.toString(2) // 10000 num.toString(8); // 20 num.toString(16); // 10 num.toString(5); // 31 虽然没有五进制,但是这样传参是可以被toString()方法接受的 1.toString(); // 会报语法错误。 (1).toString(); // '1' 1..toString(); // '1' 1.2.toString(); // '1' 在javaScript 引擎中在解释代码时对于 1.toString 会认为.是浮点数,但因小数点后面的字符是非法的 所以就会报语法上的错误。 1..toString() 和 1.2.toString() javaScript 引擎会认为第一个 . 是小数点, 第二个位属性访问。所以都能正确解释执行 纯小数的小数点后面有连续6或6个以上的“0”时,小数将用e表示法进行输出; var num = 0.000006; // 五个0 num.toString(); // 0.000006; var num = 0.0000006; // 六个0 num.toString(); // 6e-7; 浮点数整数部分的位数大于21时,输出时采用e表示法; var num = 1234567890123456789012; num.toString(); // '1.2345678901234568e+21'
知道了这个,我们知道数字转为字符串的方法,除了调用Number.prototype.toString() 可以得到一个数字字符串。还有一个钟就是直接调用 String() 构造器。 那么二者的区别是什么。
Number.prototype.toString() 是数字的方法对象调用这个toString()方法,在javaScript中所有的对象在原型上都可以找到toString这个方法,委托到构造的对象上,基本数据类型也可以通过引擎内部来实现自动封箱,使得基本数据类型可以使用toString这个方法,但是null, undefined 两个是包装对象的。他们不是对象,调用toString 就会报 TypeError 类型错误。
但是String() 构造器,可以把null, undefined 转成对应的字符串格式。即'null', 'undefined';
-
Number.prototype.valueOf
valueOf 方法返回一个被 Number 对象包装的原始值。
该方法通常是由 JavaScript 引擎在内部隐式调用的,而不是由用户在代码中显式调用的。
var numObj = new Number(10); typeof numObj; // object var num = numObj.valueOf(); num; // 10 typeof num; // number