JavaScript 内部,所有数字都是以 64 位浮点数形式储存,即使整数也是如此。所以,1
与1.0
是相同的,是同一个数。
0.1 + 0.2 === 0.3;
// false
0.3 / 0.1;
// 2.9999999999999996
(0.3 - 0.2) === 0.2 - 0.1;
// false
你知道 0.1 + 0.2 !== 0.3 是进制问题,但你讲不出个所以然,是吧?
用了一天时间,我终于彻底搞懂了 0.1 + 0.2 是否等于 0.3!
// 0.1 化为二进制:
0.000 11001100 11001100 11001100 11001100 11001100 11001100 1100 1100 11
// 0.1 保留 52 位有效数字:
0.000 11001100 11001100 11001100 11001100 11001100 11001100 1101 0
// 0.2 化为二进制:
0.00 11001100 11001100 11001100 11001100 11001100 11001100 1100 1100 11
// 0.2 保留 52 位有效数字:
0.00 11001100 11001100 11001100 11001100 11001100 11001100 1101 0
// 0.1+0.2:
0.000 11001100 11001100 11001100 11001100 11001100 11001100 1101 0
0.001 10011001 10011001 10011001 10011001 10011001 10011001 1010
————————————————————————————————————————————————————————————————————
0.010 01100110 01100110 01100110 01100110 01100110 01100110 0111 0
// 保留 52 位尾数
0.010 01100110 01100110 01100110 01100110 01100110 01100110 100 即
0.0 10011001 10011001 10011001 10011001 10011001 10011001 1010 0
// 转十进制
0.30000000000000004
// 解决方法
let value = value * Math.pow(10, props.precision);
let stepValue = stepValue * Math.pow(10, props.precision);
showValue = value + stepValue;
showValue = (showValue / Math.pow(10, props.precision)).toFixed(
props.precision
);
showValue = Number(showValue);
字面形式
0o
或0O
的数值,或者有前导 0、且只用到 0-7 的八个阿拉伯数字的数值。0x
或0X
的数值。0b
或0B
的数值。科学计数法表示
123e3; // 123000
123e-3; // 0.123
3.1e12;
0.1e-23;
0
表示,ES6 进一步明确,要使用前缀0o
表示。允许 JavaScript 的数值使用下划线(_
)作为分隔符 12345_00 === 1_234_500
数值分隔符只是一种书写便利,对于 JavaScript 内部数值的存储和输出,并没有影响。
不能放在数值的最前面(leading)或最后面(trailing)。
不能两个或两个以上的分隔符连在一起。
小数点的前后不能有分隔符。
科学计数法里面,表示指数的e
或E
前后不能有分隔符。
下面三个将字符串转成数值的函数,不支持数值分隔符。主要原因是语言的设计者认为,数值分隔符主要是为了编码时书写数值的方便,而不是为了处理外部输入的数据。
Number("123_456"); // NaN
parseInt("123_456"); // 123
0
+0
或-0
当作分母,返回的值是不相等的。+Infinity
,除以负零得到-Infinity
。NaN
是 JavaScript 的特殊值,表示“非数字”(Not a Number),主要出现在将字符串解析成数字出错的场合。NaN
不是独立的数据类型,而是一个特殊数值,它的数据类型依然属于Number
NaN
不等于任何值,包括它本身。NaN === NaN; // false
Infinity
表示“无穷”,用来表示两种场景。
Infinity
。Infinity
表示正的无穷,-Infinity
表示负的无穷。// 场景一
Math.pow(2, 1024);
// Infinity
// 场景二
0 / 0; // NaN
1 / 0; // Infinity
parseInt()
方法用于将字符串转为整数。parseFloat()
方法用于将一个字符串转为浮点数。isNaN()
方法可以用来判断一个值是否为NaN
。只对数值有效,如果传入其他值,会被先转成数值。isFinite()
方法返回一个布尔值,表示某个值是否为正常的数值。isNaN("Hello"); // true
// 相当于
isNaN(Number("Hello")); // true
Number()
将任意值转为数值: Number
本身是一个函数,可以当作工具方法使用,将任何类型的值转为数值。Number()
构造函数: Number
不仅可以当作工具函数使用,还可以当作构造函数使用,即前面可以使用new
命令。构造数值对象,用于生成值为数值的对象Number.POSITIVE_INFINITY
:正的无限,指向Infinity
。
Number.NEGATIVE_INFINITY
:负的无限,指向-Infinity
。
Number.NaN
:表示非数值,指向NaN
。
Number.MIN_VALUE
:表示最小的正数(即最接近 0 的正数,在 64 位浮点数体系中为5e-324
),相应的,最接近 0 的负数为-Number.MIN_VALUE
。
Number.MAX_SAFE_INTEGER
:表示能够精确表示的最大整数,即9007199254740991
。
Number.MIN_SAFE_INTEGER
:表示能够精确表示的最小整数,即-9007199254740991
。
Number.EPSILON
:ES6 在Number
对象上面,新增一个极小的常量,表示 1 与大于 1 的最小浮点数之间的差
1.00..001
,小数点后面有连续 51 个零。这个值减去 1 之后,就等于 2 的 -52 次方。Number.MAX_SAFE_INTEGER
:=== Math.pow(2, 53) - 1
Number.MIN_SAFE_INTEGER
:=== -Number.MAX_SAFE_INTEGER
-2^53
到2^53
之间(不含两个端点),超过这个范围,无法精确表示这个值Number.isSafeInteger()
则是用来判断一个整数是否落在上述范围之内。
Number.isFinite()
用来检查一个数值是否为有限的(finite),即不是Infinity
。
Number.isNaN()
用来检查一个值是否为NaN
。
isFinite()
和isNaN()
的区别在于
Number()
将非数值的值转为数值,再进行判断Number.isFinite()
对于非数值一律返回false
,Number.isNaN()
只有对于NaN
才返回true
,非NaN
一律返回false
。Number.parseInt()
方法用于将字符串转为整数。
Number.parseFloat()
方法用于将一个字符串转为浮点数。
parseInt()
和parseFloat()
,移植到Number
对象上面,行为完全保持不变。Number.isInteger()
用来判断一个数值是否为整数。
Number.prototype.toString()
用来将一个数值转为字符串形式,(10).toString() // "10"
10
一定要放在括号里,这样表明后面的点表示调用对象属性。如果不加括号,这个点会被 JavaScript 引擎解释成小数点,从而报错Number.prototype.toFixed()
方法先将一个数转为指定位数的小数,然后返回这个小数对应的字符串。 (10.005).toFixed(2); // "10.01"
5
的四舍五入是不确定的,使用的时候必须小心。Number.prototype.toExponential()
将一个数转为科学计数法形式Number.prototype.toPrecision()
方法用于将一个数转为指定位数的有效数字。Number.prototype.toLocaleString()
方法接受一个地区码作为参数,返回一个字符串,表示当前数字在该地区的当地书写形式。与其他对象一样,Number.prototype
对象上面可以自定义方法,被Number
的实例继承。
Math
是 JavaScript 的原生对象,提供各种数学功能。该对象不是构造函数,不能生成实例,所有的属性和方法都必须在Math
对象上调用
Math.E
:常数e
。 // 2.718281828459045Math.LN2
:2 的自然对数。 // 0.6931471805599453Math.LN10
:10 的自然对数。 // 2.302585092994046Math.LOG2E
:以 2 为底的e
的对数。 // 1.4426950408889634Math.LOG10E
:以 10 为底的e
的对数。 // 0.4342944819032518Math.PI
:常数π
。 // 3.141592653589793Math.SQRT1_2
:0.5 的平方根。 // 0.7071067811865476Math.SQRT2
:2 的平方根。 // 1.4142135623730951这些属性都是只读的,不能修改。
Math.abs()
:绝对值
Math.ceil()
:向上取整 返回大于或等于参数值的最小整数(天花板值)
Math.floor()
:向下取整 返回小于或等于参数值的最大整数(地板值)
Math.max()
:最大值
Math.min()
:最小值
Math.pow()
:幂运算 Math.pow(2, 3)
// 8
Math.sqrt()
:平方根
Math.log()
:自然对数,返回以e
为底的自然对数值
Math.exp()
:e
的指数
Math.round()
:四舍五入 // 等同于 Math.floor(x + 0.5)
, Math.round(-1.5)
// -1
Math.random()
:随机数,返回 0 到 1 之间的一个伪随机数,可能等于 0,但是一定小于 1
Math.sin()
:返回参数的正弦(参数为弧度值)
Math.cos()
:返回参数的余弦(参数为弧度值)
Math.tan()
:返回参数的正切(参数为弧度值)
Math.asin()
:返回参数的反正弦(返回值为弧度值)
Math.acos()
:返回参数的反余弦(返回值为弧度值)
Math.atan()
:返回参数的反正切(返回值为弧度值)
Math.trunc()
方法用于去除一个数的小数部分,返回整数部分。
Math.sign()
方法用来判断一个数到底是正数、负数、还是零。对于非数值,会先将其转换为数值。
Math.cbrt()
方法用于计算一个数的立方根。
Math.clz32()
方法将参数转为 32 位无符号整数的形式,然后返回这个 32 位值里面有多少个前导 0。
Math.imul()
方法返回两个数以 32 位带符号整数形式相乘的结果,返回的也是一个 32 位的带符号整数。
Math.fround()
方法返回一个数的 32 位单精度浮点数形式。
Math.hypot()
方法返回所有参数的平方和的平方根。
Math.expm1(x)
返回 ex - 1,即Math.exp(x) - 1
。
Math.log1p(x)
方法返回1 + x
的自然对数,即Math.log(1 + x)
。如果x
小于-1,返回NaN
。
Math.log10(x)
返回以 10 为底的x
的对数。如果x
小于 0,则返回 NaN。
Math.log2(x)
返回以 2 为底的x
的对数。如果x
小于 0,则返回 NaN。
Math.sinh(x)
返回x
的双曲正弦(hyperbolic sine)
Math.cosh(x)
返回x
的双曲余弦(hyperbolic cosine)
Math.tanh(x)
返回x
的双曲正切(hyperbolic tangent)
Math.asinh(x)
返回x
的反双曲正弦(inverse hyperbolic sine)
Math.acosh(x)
返回x
的反双曲余弦(inverse hyperbolic cosine)
Math.atanh(x)
返回x
的反双曲正切(inverse hyperbolic tangent)
ES2020 引入了一种新的数据类型 BigInt(大整数),来解决这个问题,这是 ECMAScript 的第八种数据类型。BigInt 只用来表示整数,没有位数的限制,任何位数的整数都可以精确表示。
n
。n
。-
),但是不能使用正号(+
),因为会与 asm.js 冲突。1234; // 普通整数
1234n; // BigInt
// BigInt 的运算
1n + 2n; // 3n
可以使用Boolean()
、Number()
和String()
这三个方法,将 BigInt 可以转为布尔值、数值和字符串类型。
取反运算符(!
)也可以将 BigInt 转为布尔值
BigInt 类型的+
、-
、*
和**
这四个二元运算符,与 Number 类型的行为一致。除法运算/
会舍去小数部分,返回一个整数
不带符号的右移位运算符>>>
,一元的求正运算符+
。上面两个运算符用在 BigInt 会报错。前者是因为>>>
运算符是不带符号的,但是 BigInt 总是带有符号的,导致该运算无意义,完全等同于右移运算符>>
。后者是因为一元运算符+
在 asm.js 里面总是返回 Number 类型,为了不破坏 asm.js 就规定+1n
会报错。
BigInt 不能与普通数值进行混合运算。
BigInt
函数,可以用它生成 BigInt 类型的数值。转换规则基本与Number()
一致,将其他类型的值转为 BigInt。BigInt()
函数必须有参数,而且参数必须可以正常转为数值,BigInt.prototype.toString()
BigInt 继承了 Object 对象的两个实例方法。
BigInt.prototype.valueOf()
BigInt 继承了 Object 对象的两个实例方法。
BigInt.prototype.toLocaleString()
它还继承了 Number 对象的一个实例方法。
BigInt.asUintN(width, BigInt)
: 给定的 BigInt 转为 0 到 2width - 1 之间对应的值。BigInt.asIntN(width, BigInt)
:给定的 BigInt 转为 -2width - 1 到 2width - 1 - 1 之间对应的值。BigInt.parseInt(string[, radix])
:近似于Number.parseInt()
,将一个字符串转换成指定进制的 BigInt。