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