JavaScript中的数值

2023-08-20  本文已影响0人  程序员之家

JavaScript中的主要数值类型是Number类型,用于表示整数和近似的实数。JavaScript采用了由IEEE 754标准定义的64位浮点格式来表示数值。这意味着JavaScript可以表示最大整数±1.797 693 134 862 315 7 × 10^308和最小整数±5 × 10^-324。

JavaScript中的这种数值格式允许我们准确表示介于-9,007,199,254,740,992(-2^53)和9,007,199,254,740,992(2^53)之间的所有整数。如果您的值超出此范围,可能会在最低有效位处丧失一些精度。

当一个数值直接出现在JavaScript程序中时,它被称为“数值字面量”。请注意,任何数值字面量都可以在前面加上减号(-)以使值为负。

1. 整数字面量.

在JavaScript程序中,十进制整数可以直接写为数字序列。例如:

0

3

10000000

除了十进制整数字面量,JavaScript还支持十六进制(基数16)的值。十六进制字面量以0x或0X开头,后面跟着十六进制数字字符串。十六进制数字由数字0到9和字母a(或A)到f(或F)组成,其中a到f代表10到15。以下是十六进制整数字面量的示例:

//=> 255:(15*16 + 15)

0xff

//=> 195939070

0xBADCAFE

在ES6及更高版本中,您还可以使用前缀0b和0o(或0B和0O)来表示二进制(基数2)或八进制(基数8)的整数:

//=> 21:(1*16 + 0*8 + 1*4 + 0*2 + 1*1)

0b10101

//=> 255:(3*64 + 7*8 + 7*1)

0o377

(程序员的软技能:ke.qq.com/course/6034346)

2. 浮点数字面量.

浮点数字面量可以包含小数点,并遵循实数的传统语法。实数由数字的整数部分、小数点和数字的小数部分组成。

浮点数字面量还可以使用指数表示法,其中实数后跟字母e(或E),一个可选的加号或减号,以及一个整数指数。这种表示法表示实数乘以10的指数次幂。

更简洁的语法形式为:

[digits][.digits][(E|e)[(+|-)]digits]

例如:

3.14

2345.6789

.333333333333333333

//6.02 x 10^23

6.02e23

//1.4738223 x 10^-32

1.4738223E-32

您可以使用下划线来分隔数值字面量的各个部分,这是一种已进入标准化后期并受到所有主要浏览器和Node实现支持的功能:

// 使用下划线作为千分位分隔符

let billion = 1_000_000_000;

// 使用下划线作为字节分隔符

let bytes = 0x89_AB_CD_EF;

// 使用下划线作为半字节分隔符

let bits = 0b0001_1101_0111;

// 也可以用于小数部分

let fraction = 0.123_456_789;

(程序员的软技能:ke.qq.com/course/6034346)

3. JavaScript中的算术运算。

JavaScript程序使用语言提供的算术运算符来操作数值。这些运算符包括加法+、减法-、乘法*、除法/和取模(除法后的余数)%。ES2016引入了指数运算符**。

除了这些基本的算术运算符,JavaScript还通过Math对象提供了一组函数和常量,以支持更复杂的数学计算:

// => 9007199254740992:2的53次方

Math.pow(2, 53)

// => 1.0:四舍五入到最近的整数

Math.round(0.6)

// => 1.0:向上取整到最近的整数

Math.ceil(0.6)

// => 0.0:向下取整到最近的整数

Math.floor(0.6)

// => 5:绝对值

Math.abs(-5)

// 返回提供参数的最大值

Math.max(x, y, z)

// 返回提供参数的最小值

Math.min(x, y, z)

// 伪随机数x,其中0 <= x < 1.0

Math.random()

// π:代表数学常数π的常量

Math.PI

// e:代表自然对数的底数e的常量

Math.E

// => 3**0.5:3的平方根

Math.sqrt(3)

// => 3**(1/3):3的立方根

Math.pow(3, 1/3)

// 三角函数:还有Math.cos、Math.atan等

Math.sin(0)

// 10的自然对数

Math.log(10)

// 以10为底的100的对数

Math.log(100) / Math.LN10

// 以2为底的512的对数

Math.log(512) / Math.LN2

// Math.E的立方

Math.exp(3)

ES6在Math对象上引入了一组新的函数:

// => 3:立方根

Math.cbrt(27)

// => 5:一组参数平方和的平方根

Math.hypot(3, 4)

// => 2:以10为底的对数

Math.log10(100)

// => 10:以2为底的对数

Math.log2(1024)

// (1+x)的自然对数:对于非常小的x很精确

Math.log1p(x)

// Math.exp(x) - 1;Math.log1p()的反函数

Math.expm1(x)

// 根据参数的符号返回-1、0或1

Math.sign(x)

// => 6:优化的32位整数乘法

Math.imul(2, 3)

// => 28:32位二进制表示中前导零位的数量

Math.clz32(0xf)

// => 3:去掉小数部分以得到整数

Math.trunc(3.9)

// 四舍五入到最近的32位浮点值

Math.fround(x)

// 双曲正弦,还有Math.cosh()和Math.tanh()

Math.sinh(x)

// 双曲反正弦,还有Math.acosh()和Math.atanh()

Math.asinh(x)

在JavaScript中,算术不会在遇到溢出、下溢或除以零时抛出错误。当数值操作的结果超出可表示范围(溢出)时,结果是特殊的无限值Infinity。类似地,当负数的绝对值超出负数的可表示范围(下溢)时,结果为负无穷-Infinity。这两个无限值的行为符合预期:涉及加法、减法、乘法或除法的任何算术运算都会导致无限值(尽管符号可能会改变)。

当数值操作的结果接近零但仍大于最小可表示数时,发生下溢。在这种情况下,JavaScript返回0。如果下溢发生在倒数的情况下,JavaScript返回一个称为“负零”的特殊值。这个值与普通零几乎无法区分,对于JavaScript程序员来说很少会引起关注。

在JavaScript中,除以零不是错误;它只会导致无限或负无穷。然而,有一个例外:将0除以0会得到一个称为“非数”(NaN)的特殊值。此外,类似无限除以无限、负数的平方根或在算术运算中使用NaN作为操作数等操作都会产生NaN作为结果。

JavaScript预定义了全局常量Infinity和NaN,分别对应正无穷大和非数。这些值也可以通过Number对象的属性访问:

// 由于过大无法表示,得到正无穷大

Infinity

// 与上面相同

Number.POSITIVE_INFINITY

// => Infinity

1 / 0

// => Infinity;溢出

Number.MAX_VALUE * 2

// 由于过大无法表示为负数,得到负无穷大

-Infinity

// 与上面相同

Number.NEGATIVE_INFINITY

// => -Infinity

-1 / 0

// => -Infinity

-Number.MAX_VALUE * 2

// NaN:非数

NaN

// 与上面相同,不同的语法

Number.NaN

// => NaN

0 / 0

// => NaN

Infinity / Infinity

// => 0:下溢

Number.MIN_VALUE / 2

// => -0:负零

-Number.MIN_VALUE / 2

// => -0:也是负零

-1 / Infinity

//

-0

ES6在Number对象上引入了以下属性:

// 与全局parseInt()函数相同

Number.parseInt()

// 与全局parseFloat()函数相同

Number.parseFloat()

// 检查x是否为NaN

Number.isNaN(x)

// 检查x是否为有限数

Number.isFinite(x)

// 检查x是否为整数

Number.isInteger(x)

//

Number.isSafeInteger(x)

// => -(2**53 - 1)

Number.MIN_SAFE_INTEGER

// => 2**53 - 1

Number.MAX_SAFE_INTEGER

// => 2**-52:两个可表示数之间的最小差值

Number.EPSILON

在JavaScript中,NaN具有一种不寻常的特性:它既不等于任何值,也不等于自身。这意味着您不能通过使用x === NaN比较来确定变量x是否为NaN。相反,您必须使用x != x或Number.isNaN(x)来测试NaN。这两个表达式只在x与全局常量NaN具有相同值时才返回true。

全局函数isNaN()与Number.isNaN()类似。当参数为NaN或参数为不能转换为数字的非数值时,它返回true。相关的函数Number.isFinite()在参数不是NaN、Infinity或-Infinity时返回true。全局函数isFinite()在参数为有限数或可转换为有限数的值时返回true。

负零具有稍微不寻常的行为。它被认为等于正零(即使在JavaScript中使用严格相等比较),这意味着除了作为除数的角色外,很难区分这两个值:

// 普通零

let zero = 0;

// 负零

let negz = -0;

// => true:零等于负零

zero === negz

// => false:Infinity不等于负无穷

1 / zero === 1 / negz

(程序员的软技能:ke.qq.com/course/6034346)

4. 二进制浮点数和舍入误差。

实数是无限多的,但JavaScript的浮点数格式只能表示其中的有限子集(确切地说,它可以表示多达18,437,736,874,454,810,627个不同的值)。这意味着当您在JavaScript中使用实数时,您操作的数值通常是实际值的近似值。

JavaScript(以及所有现代编程语言)使用IEEE-754浮点表示,这是一种二进制表示。这种表示可以准确地表示像1/2、1/8和1/1024这样的分数。然而,我们常用的最常见的分数(尤其是在财务计算中)是十进制分数,如1/10、1/100等。二进制浮点表示无法精确表示甚至简单的数字如0.1。

虽然JavaScript的数值具有足够的精度,可以非常接近地近似0.1,但不能完全表示它。这可能会导致问题,如以下代码所示:

// 30美分减去20美分

let x = 0.3 - 0.2;

// 20美分减去10美分

let y = 0.2 - 0.1;

// => false:这两个值不相等!

x === y

// => false:.3 - .2不等于.1

x === 0.1

// => true:.2 - .1等于.1

y === 0.1

由于舍入误差,近似值0.3和0.2之间的差异不等于近似值0.2和0.1之间的差异。这不是JavaScript特定的问题;这是所有使用二进制浮点数的编程语言的常见问题。还要注意,上述代码中的x和y的值非常接近,它们非常接近正确的值。计算出的值对于大多数目的来说都是完全合适的,但不建议尝试比较它们的精确相等性。

如果近似浮点值在您的程序中造成问题,您可以考虑使用等价的整数。例如,在处理与货币相关的计算时,您可以使用以分为单位的整数表示,而不是以美元的一部分为单位的分数。

(程序员的软技能:ke.qq.com/course/6034346)

5. 用BigInt表示任意精度整数。

在ES2020中,JavaScript引入了一种新的数字类型,称为BigInt。截至2020年初,Chrome、Firefox、Edge和Node.js已经实现了这种类型,Safari也在进行相关工作。正如名称所示,BigInt值是整数。添加此类型的主要动机是为了表示64位整数,这对于与许多其他语言和API的兼容性至关重要。然而,BigInt值可以具有数千甚至数百万位的数字,以满足大数值的需求(尽管BigInt实现不适合用于加密,因为它们不考虑防御定时攻击)。

BigInt字面量由一系列数字后跟小写字母"n"组成。默认情况下,基数为10,但您可以使用前缀0b、0o和0x分别表示二进制、八进制和十六进制的BigInt:

// 一个不太大的BigInt字面量

1234n

// 二进制BigInt

0b111111n

// 八进制BigInt

0o7777n

// => 2n ** 63n:一个64位整数

0x8000000000000000n

您可以使用BigInt()函数将常规JavaScript数字或字符串转换为BigInt值:

// => 9007199254740991n

BigInt(Number.MAX_SAFE_INTEGER)

// 一个由1后面跟100个零组成的数字

let string = "1" + "0".repeat(100);

// => 10n ** 100n:一个天文数字

BigInt(string)

与BigInt值的算术操作类似于常规JavaScript数字操作,除法除去余数并朝向零四舍五入:

// => 3000n

1000n + 2000n

// => 1000n

3000n - 2000n

// => 6000000n

2000n * 3000n

// => 3n:商为3

3000n / 997n

// => 9n:余数为9

3000n % 997n

// 一个有39457位的梅森素数

(2n ** 131071n) - 1n

尽管标准的+、-、*、/、%和**运算符适用于BigInt,但您不能将BigInt操作数与常规数字操作数混合使用。乍看起来,这个规则可能有点奇怪,但实际上是合理的。如果一个数值类型比另一个更通用,那么定义混合操作数计算并返回更通用的类型是很容易的。然而,在这种情况下,这两种类型都不比另一种更通用:BigInt可以表示非常大的值,使其在常规数值类型之间更通用。但是BigInt只能表示整数,这使得常规JavaScript数值类型在这个方面更通用。这种困境无法解决,因此在使用算术运算符时,JavaScript简单地禁止混合使用这两种操作数类型。

另一方面,比较运算符允许混合操作数类型:

// => true

1 < 2n

// => true

2 > 1n

// => true

0 == 0n

// => false:===还检查类型相等性

0 === 0n

位运算符通常可以与BigInt操作数一起使用。然而,Math对象的函数中没有一个接受BigInt操作数。

(程序员的软技能:ke.qq.com/course/6034346)

6. 日期和时间。

JavaScript提供了一个简单的Date类,用于表示和操作与日期和时间有关的数据。JavaScript的Date是一个对象,但它也具有一个数值表示,称为时间戳,它是自1970年1月1日以来的毫秒数:

// 当前时间的时间戳(数值)

let timestamp = Date.now();

// 当前时间的Date对象

let now = new Date();

// 转换为毫秒时间戳

let ms = now.getTime();

// 转换为ISO格式的字符串

let iso = now.toISOString();

(程序员的软技能:ke.qq.com/course/6034346)

上一篇下一篇

猜你喜欢

热点阅读