JavaScript数值 - JavaScript权威指南(第七版)读书笔记 第三章

JavaScript中的主要数值类型是Number,用于表示整数和近似实数。JavaScript使用IEEE 754标准定义的64位浮点格式表示数值,这意味着它可以表示的最大整数是±1.7976931348623157 x 10^308,最小整数是±5 x 10^-324。这个范围内的所有整数(包括边界值)都可以被准确表示,但超出这个范围的整数可能会丢失一些精度,因为JavaScript中的数值精度是有限的。

在JavaScript中,数值字面量(numeric literal)指的是数值真正出现在代码中的地方。JavaScript支持多种形式的数值字面量,例如整数、浮点数等。需要注意的是,任何数值字面量前都可以加上一个减号(-)以表示负值。

另外,尽管JavaScript可以表示很大范围的整数,但某些操作(比如数组索引和位操作)是以32位整数计算的。如果需要准确表示更大的整数,可以考虑使用其他方法或库来处理。

证书字面量

JavaScript中可以直接使用十进制整数字面量,以数字序列的形式表示,比如:

  • 0
  • 3
  • 10900000

除了十进制整数字面量,JavaScript还支持十六进制(基数为16)、二进制(基数为2)和八进制(基数为8)的整数字面量。

十六进制字面量以0x或0X开头,后跟一个十六进制数字串,其中十六进制数字包括0到9以及字母a到f(大小写不敏感,即A到F也可以),分别表示10到15。例如:

  • 0xff // 对应十进制数值为255
  • 0XBADCAFE // 对应十进制数值为19593907

ES6及之后的版本中,还可以使用二进制和八进制字面量表示整数。二进制使用前缀0b(或0B),八进制使用前缀0o(或0O)。例如:

  • 0b10101 // 对应十进制数值为21
  • 0o377 // 对应十进制数值为255

这些不同进制的整数字面量提供了在代码中以不同进制表示整数的灵活性

浮点字面量

JavaScript中的浮点字面量可以包含小数点,它们使用传统的实数语法表示。实数值由整数部分、小数点和小数部分组成。

另外,浮点字面量还可以使用指数记数法表示,即在实数值后面可以跟着字母e(或E),再跟一个可选的加号或减号,最后跟着一个整数指数。这种记数法表示的是实数值乘以10的指数次方。举个例子:

  • 3.14
  • 2345.6789
  • .333333333333333333
  • 6.62e23 (对应6.62乘以10的23次方)
  • 1.4738223E-32 (对应1.4738223乘以10的-32次方)

在JavaScript中,数值字面量的分隔符可以用下划线将数值分隔为更易读的数字段。这个特性在2020年年初写作本书时尚未成为官方的JavaScript标准,但已经进入了标准化流程的后期,并且已经被所有主流浏览器以及Node.js实现支持。举例来说:

let billion = 1_000_000_000; // 使用下划线作为千分位分隔符
let bytes = 0x89_AB_CD_EF; // 作为字节分隔符
let bits = 0b00_01_1101_0111; // 作为半字节分隔符
let fraction = 0.123_456_789; // 在小数部分也可以使用下划线

这种用下划线分隔数值的语法形式可以增强代码的可读性和可维护性。

JavaScript中的算术

JavaScript 中算术操作符、Math 对象的属性以及一些数值常量和函数的介绍。

Math.pow(2,53) // => 9007199254740992:2 的 53 次方
Math.round(.6) // => 1.0:舍入到最接近的整数
Math.ceil(.6) // => 1.6:向上舍入到一个整数
Math.floor(.6) // => 0.0:向下舍入到一个整数
Math.abs(-5) // => 5:绝对值
Math.max(x,y,z) // 返回最大的参数
Math.min(x,y,z) // 返回最小的参数
Math.random() // 伪随机数 X,其中 0 <= X < 1.0
Math.PI // 圆周率
Math.E // e:自然对数的底数
Math.sqrt(3) // => 3**0.5:3的平方根
Math.pow(3, 1/3) // => 3**(1/3):3 的立方根
Math.sin(0) // => 0:三角函数之一,这里是正弦函数
Math.log(100) // => 4.605:M 的自然对数

Es6中新增的函数

  • Math.cbrt(27):返回给定数字的立方根,即 3。
  • Math.hypot(3, 4):返回所有参数平方和的平方根,即 5。
  • Math.log10(100):返回以 10 为底的对数,即 2。
  • Math.log2(1024):返回以 2 为底的对数,即 10。
  • Math.log1p(x):返回 (1 + x) 的自然对数,精确到非常小的 x。
  • Math.expm1(x):返回 Math.exp(x) - 1,是 Math.log1p() 的逆运算。
  • Math.sign(x):对于大于、等于或小于 0 的参数,返回 1、0 或 -1。
  • Math.imul(2, 3):返回优化的 32 位整数乘法,即 6。
  • Math.clz32(0xf):返回 32 位整数中前导 0 的位数,即 28。
  • Math.trunc(3.9):返回去除分数部分得到的整数,即 3。
  • Math.fround(x):将参数舍入为最接近的 32 位浮点数。
  • Math.sinh(x):返回双曲正弦。
  • Math.asinh(x):返回双曲反正弦。

JavaScript 中的数值运算在遇到上溢出、下溢出或被零除时不会报错,而是会返回特殊的值。以下是对这些情况的详细说明:

  1. 上溢出:当数值操作的结果超过了 JavaScript 能表示的最大值时,结果会变成特殊的无穷大值 Infinity。类似地,当某个负数的绝对值超过了 JavaScript 能表示的最小负值时,结果是负无穷大值 -Infinity。这两个无穷值的行为符合预期:无论对无穷大值进行加、减、乘、除运算,结果仍然是无穷大值,只是符号可能会相反。
  2. 下溢出:当数值操作的结果比 JavaScript 能表示的最小数值还要接近零时,JavaScript 会返回 0。如果下溢出是由负数引起的,JavaScript 会返回一个被称为 "负零" 的特殊值。负零与普通的零几乎完全一样,但在特定情况下可能需要注意。
  3. 被零除:在 JavaScript 中,被零除不会报错,而是简单地返回无穷大值或负无穷大值。然而,当被零除的操作数是 0 时,结果会是一个特殊的非数值(NaN,Not a Number)。
  4. 无穷值除以无穷值、负数的平方根、或者无法转换为数值的非数值:这些操作的结果都是 NaN。

JavaScript 预定义了全局常量 Infinity 和 NaN 来表示正无穷和非数值。这些值也可以通过 Number 对象的属性获取:

  • Infinity:表示正无穷大。
  • Number.POSITIVE_INFINITY:与 Infinity 相同。
  • 1/0:等价于 Infinity。
  • Number.MAX_VALUE * 2:超出了最大可表示的正数范围,返回 Infinity。
  • -Infinity:表示负无穷大。
  • Number.NEGATIVE_INFINITY:与 -Infinity 相同。
  • -1/0:等价于 -Infinity。
  • -Number.MAX_VALUE * 2:超出了最小可表示的负数范围,返回 -Infinity。
  • NaN:表示非数值。
  • Number.NaN:与 NaN 相同。
  • 0/0:等价于 NaN。
  • Infinity/Infinity:等价于 NaN。
  • Number.MIN_VALUE/2:下溢出,返回 0。
  • -Number.MIN_VALUE/2:负零。
  • -1/Infinity:负零。
  • -0:也是负零。

ES6定义了下面的number属性

  • Number.parseInt():类似于全局的 parseInt() 函数,用于将字符串转换为整数。
  • Number.parseFloat():类似于全局的 parseFloat() 函数,用于将字符串转换为浮点数。
  • Number.isNaN(x):判断 x 是否为 NaN,返回布尔值。
  • Number.isFinite(x):判断 x 是否为有限数值(不是 NaN、Infinity 或 -Infinity),返回布尔值。
  • Number.isInteger(x):判断 x 是否为整数,返回布尔值。
  • Number.isSafeInteger(x):判断 x 是否为安全整数,即在 -2^53 和 2^53 - 1 之间,返回布尔值。
  • Number.MAX_SAFE_INTEGER:安全整数的最大值,等于 2^53 - 1。
  • Number.MIN_SAFE_INTEGER:安全整数的最小值,等于 -2^53 + 1。
  • Number.EPSILON:数值间的最小差异,即 JavaScript 可表示的最小精度。

此外,文本提到了 NaN 与任何值的比较都不相等,包括自身。因此,要判断某个值是否为 NaN,不能使用 X === NaN,而应该使用 X !== X 或 Number.isNaN(x)。

函数 isNaN() 和 Number.isNaN() 类似,它们都用于判断一个值是否为 NaN。isNaN() 在参数为 NaN 或无法转换为数字的字符串时返回 true,而 Number.isNaN() 只在参数为 NaN 时返回 true。

有意思的是在 JavaScript 中,负零值与正零值在大多数情况下被视为相等,即使使用严格相等比较运算符(===)也是如此。这意味着除了在除法运算中使用负零值作为除数时,几乎无法区分这两个值。

let zero = 0; // 常规的零值,即正零
let negz = -0; // 负零值

// 比较正零和负零是否相等
console.log(zero === negz); // 输出结果为 true

// 比较 1 除以正零和负零的结果是否相等
console.log(1 / zero === 1 / negz); // 输出结果为 false

二进制浮点数与舍入错误

JavaScript 使用 IEEE-754 标准的浮点数表示法,这种表示法在表示实数时是有限的,只能精确表示其中有限个实数。具体来说,JavaScript 可以精确表示约为 18 437 736 874 454 810 627 个不同的实数(它们分别占据32位和64位存储空间)。这就意味着在操作实数时,JavaScript 可能会使用近似值来表示实际数值,因为实数是无限的,而 JavaScript 的浮点格式是有限的。

虽然二进制浮点数可以精确地表示某些分数,比如 1/2、1/8 和 1/1024 等,但对于我们通常使用的十进制分数(比如 1/10、1/100),二进制浮点数却无法精确表示。这就意味着即使 JavaScript 的数值能够非常接近 0.1,但无法精确地表示它

就会导致以下的问题

let X = 0.3;
let y = 0.2;

// 30美分减2美分
let result1 = X - 0.2;
// 20美分减10美分
let result2 = y - 0.1;

console.log(result1 === result2); // => false:这两个值不一样!
console.log(result1 === 0.1);     // => false:.3 - .2 不等于 .1
console.log(result2 === 0.1);     // => true:.2 - .1 等于 .1

解决方案:

如果浮点近似值对程序产生了问题,一种解决方案是考虑使用等价的整数形式。例如,在涉及到货币计算时,可以使用整数形式的货币单位,如美分,而不是小数形式的美元。这样可以避免浮点数带来的舍入误差问题。

通过BigInt表示任意精度整数

Bigint 是 JavaScript 中的一种数值类型,用于表示任意精度的整数。它的引入是为了解决 JavaScript 中整数表示范围有限的问题。Bigint 可以表示非常大的整数,甚至可以达到数千万位。但需要注意的是,Bigint 并不适合用于加密,因为它们不考虑防止时序攻击。

Bigint 的字面量写作一串数字后跟小写字母 n。默认情况下,这些数字的基数是十进制,但可以通过前缀 0b、0o 和 0x 来表示二进制、八进制和十六进制的 Bigint。

1234n // 一个不太大的 Bigint 字面量
0b111111111111111n // 二进制 Bigint
0o7777n // 八进制 Bigint
0x8000000000000000n // => 2n**63n:一个 64 位整数

可以使用 BigInt() 函数将常规 JavaScript 数值或字符串转换为 Bigint 值。例如,BigInt(Number.MAX_SAFE_INTEGER) 将最大安全整数转换为 Bigint,BigInt(string) 可以将字符串转换为对应的 Bigint 值。

BigInt(Number.MAX_SAFE_INTEGER)
BigInt(string)

Bigint 的算术运算与常规 JavaScript 数值的算术运算类似,支持加、减、乘、除和取模操作。需要注意的是,除法会丢弃余数并向下舍入。例如,3000n / 997n 的结果是 3n

1000n + 2000n // => 3000n
3000n - 2000n // => 1000n
2000n * 3000n // => 6000000n
3000n / 997n  // => 3n;商是 3
3000n % 997n  // => 9n;余数是 9

尽管标准的算术操作符可以用于 Bigint,但不能混合使用 Bigint 操作数和常规数值操作数。这是因为 Bigint 和常规数值类型并不比另一种更通用,因此 JavaScript 不允许在使用算术操作符时混合使用这两种类型的操作数。

位操作符通常可以用于 Bigint 操作数。这意味着像按位与 (&)、按位或 (|)、按位异或 (^)、按位左移 (<<) 和按位右移 (>>) 这样的操作符可以接受 Bigint 类型的操作数,并按位进行操作。

但需要注意的是,Math 对象的任何函数都不接受 Bigint 操作数

日期和时间

JavaScript 提供了一个简单的 Date 类来表示日期和时间。Date 是一个对象,可以用来表示特定的日期和时间点。使用 Date 类可以方便地获取当前时间或者指定的时间点,并进行各种日期和时间的操作。

时间戳

在 JavaScript 中,日期和时间可以用自 1970 年 1 月 1 日起至今的毫秒数来表示,这个数值被称为时间戳。时间戳表示了从 1970 年 1 月 1 日 00:00:00 UTC(世界标准时间)开始经过的毫秒数。

let timestamp = Date.now(); // 当前时间的时间戳(数值)
let now = new Date(); // 当前时间的 Date 对象
let ms = now.getTime(); // 转换为毫秒时间戳
let Iso = now.toISOString(); // 转换为标准格式的字符串

  • 30
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值