数字和日期

本章介绍了用于处理和执行数字和日期计算的JavaScript概念、对象和函数。这包括使用以各种进制(包括十进制、二进制和十六进制)编写的数字,以及使用全局Math对象对数字执行各种数学运算。

数字

在JavaScript中,数字以双精度64位二进制格式IEEE 754(即,介于±2^−1022和±2^+1023之间的数字,或大约±10^−308到±10^+308,数值精度为53位)实现。最多±2^53 − 1的整数值可以精确表示。

除了能够表示浮点数之外,number类型还有三个符号值:Infinity-InfinityNaN(非数字)。

另请参阅JavaScript数据类型和结构,以了解JavaScript中其他基本类型的上下文。

您可以使用四种类型的数字字面量:十进制、二进制、八进制和十六进制。

十进制数

js
1234567890
42

十进制字面量可以以零(0)开头,后跟另一个十进制数字,但如果前导0之后的数字都小于8,则该数字将被解释为八进制数。这被认为是遗留语法,并且以0为前缀的数字字面量(无论解释为八进制还是十进制),都会在严格模式中导致语法错误——因此,请改用0o前缀。

js
0888 // 888 parsed as decimal
0777 // parsed as octal, 511 in decimal

二进制数

二进制数语法使用前导零,后跟小写或大写拉丁字母“B”(0b0B)。如果0b之后的数字不是0或1,则会抛出以下SyntaxError:“0b之后缺少二进制数字”。

js
0b10000000000000000000000000000000 // 2147483648
0b01111111100000000000000000000000 // 2139095040
0B00000000011111111111111111111111 // 8388607

八进制数

八进制数的标准语法是以0o为前缀。例如

js
0O755 // 493
0o644 // 420

八进制数还有一个遗留语法——通过以零为前缀:0644 === 420"\045" === "%"。如果0之后的数字超出0到7的范围,则该数字将被解释为十进制数。

js
const n = 0755; // 493
const m = 0644; // 420

严格模式禁止此八进制语法。

十六进制数

十六进制数语法使用前导零,后跟小写或大写拉丁字母“X”(0x0X)。如果0x之后的数字超出范围(0123456789ABCDEF),则会抛出以下SyntaxError:“标识符紧跟在数字字面量之后开始”。

js
0xFFFFFFFFFFFFFFFFF // 295147905179352830000
0x123456789ABCDEF   // 81985529216486900
0XA                 // 10

指数运算

js
0e-5   // 0
0e+5   // 0
5e1    // 50
175e-2 // 1.75
1e3    // 1000
1e-3   // 0.001
1E3    // 1000

Number 对象

内置的Number对象具有数值常量的属性,例如最大值、非数字和无穷大。您不能更改这些属性的值,您可以按以下方式使用它们

js
const biggestNum = Number.MAX_VALUE;
const smallestNum = Number.MIN_VALUE;
const infiniteNum = Number.POSITIVE_INFINITY;
const negInfiniteNum = Number.NEGATIVE_INFINITY;
const notANum = Number.NaN;

您始终如上所示引用预定义Number对象的属性,而不是作为您自己创建的Number对象的属性。

下表总结了Number对象的属性。

属性 描述
Number.MAX_VALUE 可表示的最大正数(1.7976931348623157e+308
Number.MIN_VALUE 可表示的最小正数(5e-324
Number.NaN 特殊的“非数字”值
Number.NEGATIVE_INFINITY 特殊的负无穷大值;溢出时返回
Number.POSITIVE_INFINITY 特殊的正无穷大值;溢出时返回
Number.EPSILON 1与大于1且可以表示为Number的最小值之间的差(2.220446049250313e-16
Number.MIN_SAFE_INTEGER JavaScript中的最小安全整数(−2^53 + 1,或−9007199254740991
Number.MAX_SAFE_INTEGER JavaScript中的最大安全整数(+2^53 − 1,或+9007199254740991
方法 描述
Number.parseFloat() 解析字符串参数并返回浮点数。与全局parseFloat()函数相同。
Number.parseInt() 解析字符串参数并返回指定基数或基数的整数。与全局parseInt()函数相同。
Number.isFinite() 确定传递的值是否为有限数。
Number.isInteger() 确定传递的值是否为整数。
Number.isNaN() 确定传递的值是否为NaN。原始全局isNaN()的更强大版本。
Number.isSafeInteger() 确定提供的值是否为安全整数

Number原型提供了用于以各种格式从Number对象检索信息的方法。下表总结了Number.prototype的方法。

方法 描述
toExponential() 返回表示以指数表示法的数字的字符串。
toFixed() 返回表示以定点表示法的数字的字符串。
toPrecision() 返回表示以定点表示法指定精度的数字的字符串。

Math 对象

内置的Math对象具有用于数学常量和函数的属性和方法。例如,Math对象的PI属性的值为π(3.141…),您将在应用程序中使用它,如下所示

js
Math.PI;

类似地,标准数学函数是Math的方法。这些包括三角函数、对数函数、指数函数和其他函数。例如,如果您想使用三角函数正弦,您可以编写

js
Math.sin(1.56);

请注意,Math的所有三角方法都以弧度为单位接受参数。

下表总结了Math对象的方法。

Math的方法
方法 描述
abs() 绝对值
sin()cos()tan() 标准三角函数;参数以弧度为单位。
asin()acos()atan()atan2() 反三角函数;返回值以弧度为单位。
sinh()cosh()tanh() 双曲函数;参数为双曲角。
asinh()acosh()atanh() 反双曲函数;返回值为双曲角。

pow()exp()expm1()log()log10()log1p()log2()

指数和对数函数。
floor()ceil() 返回小于/大于或等于参数的最大/最小整数。
min()max() 返回作为参数的逗号分隔数字列表的最小值或最大值。
random() 返回 0 到 1 之间的随机数。
round()fround()trunc() 舍入和截断函数。
sqrt()cbrt()hypot() 平方根,立方根,平方参数和的平方根。
sign() 数字的符号,指示数字是正数、负数还是零。
clz32(),
imul()
32 位二进制表示中前导零位的数量。
两个参数的类似 C 语言的 32 位乘法的结果。

与许多其他对象不同,您永远不会创建自己的 Math 对象。您始终使用内置的 Math 对象。

BigInt

数值的一个缺点是它们只有 64 位。在实践中,由于使用 IEEE 754 编码,它们无法精确地表示大于 Number.MAX_SAFE_INTEGER(即 253 - 1)的任何整数。为了解决编码二进制数据以及与提供宽整数(如 i64(64 位整数)和 i128(128 位整数))的其他语言进行互操作的需求,JavaScript 还提供了另一种数据类型来表示任意大的整数BigInt

BigInt 可以定义为以 n 为后缀的整数字面量

js
const b1 = 123n;
// Can be arbitrarily large.
const b2 = -1234567890987654321n;

BigInt 也可以使用 BigInt 构造函数从数值或字符串值构建。

js
const b1 = BigInt(123);
// Using a string prevents loss of precision, since long number
// literals don't represent what they seem like.
const b2 = BigInt("-1234567890987654321");

从概念上讲,BigInt 只是一个任意长的位序列,它编码一个整数。您可以安全地执行任何算术运算,而不会丢失精度或溢出/下溢。

js
const integer = 12 ** 34; // 4.9222352429520264e+36; only has limited precision
const bigint = 12n ** 34n; // 4922235242952026704037113243122008064n

与数字相比,BigInt 值在表示大整数时具有更高的精度;但是,它们不能表示浮点数。例如,除法将四舍五入为零

js
const bigintDiv = 5n / 2n; // 2n, because there's no 2.5 in BigInt

Math 函数不能用于 BigInt 值。有一个 开放提案 来重载某些 Math 函数(如 Math.max())以允许 BigInt 值。

在 BigInt 和数字之间进行选择取决于您的用例和输入的范围。数字的精度应该能够满足大多数日常任务,而 BigInt 最适合处理二进制数据。

表达式和运算符 部分或 BigInt 参考 中了解更多有关您可以使用 BigInt 值执行的操作。

Date 对象

JavaScript 没有日期数据类型。但是,您可以使用 Date 对象及其方法在应用程序中处理日期和时间。Date 对象有大量用于设置、获取和操作日期的方法。它没有任何属性。

JavaScript 处理日期的方式与 Java 类似。这两种语言有许多相同日期方法,并且两种语言都将日期存储为自 1970 年 1 月 1 日午夜(UTC)以来的毫秒数,Unix 时间戳是自同一时刻以来的秒数。1970 年 1 月 1 日午夜(UTC)的时刻称为 纪元

Date 对象的范围相对于纪元为 -100,000,000 天到 100,000,000 天。

要创建一个 Date 对象

js
const dateObjectName = new Date([parameters]);

其中 dateObjectName 是正在创建的 Date 对象的名称;它可以是新对象或现有对象的属性。

在不使用 new 关键字的情况下调用 Date 会返回一个表示当前日期和时间的字符串。

前面语法中的 parameters 可以是以下任何一个

  • 无:创建今天的日期和时间。例如,today = new Date();
  • 表示日期的字符串,有多种不同的形式。支持的确切形式因引擎而异,但始终支持以下形式:YYYY-MM-DDTHH:mm:ss.sssZ。例如,xmas95 = new Date("1995-12-25")。如果您省略小时、分钟或秒,则该值将设置为零。
  • 一组表示年份、月份和日期的整数值。例如,xmas95 = new Date(1995, 11, 25)
  • 一组表示年份、月份、日期、小时、分钟和秒的整数值。例如,xmas95 = new Date(1995, 11, 25, 9, 30, 0);

Date 对象的方法

用于处理日期和时间的功能Date 对象方法分为以下几大类

  • "set" 方法,用于在 Date 对象中设置日期和时间值。
  • "get" 方法,用于从 Date 对象获取日期和时间值。
  • "to" 方法,用于从 Date 对象返回字符串值。
  • parse 和 UTC 方法,用于解析 Date 字符串。

使用 "get" 和 "set" 方法,您可以分别获取和设置秒、分、时、月日、星期几、月和年。有一个 getDay 方法返回星期几,但没有相应的 setDay 方法,因为星期几是自动设置的。这些方法使用整数表示这些值,如下所示

  • 秒和分:0 到 59
  • 小时:0 到 23
  • 日期:0(星期日)到 6(星期六)
  • 日期:1 到 31(月日)
  • 月份:0(一月)到 11(十二月)
  • 年份:自 1900 年以来的年份

例如,假设您定义以下日期

js
const xmas95 = new Date("1995-12-25");

然后 xmas95.getMonth() 返回 11,而 xmas95.getFullYear() 返回 1995。

getTimesetTime 方法对于比较日期很有用。getTime 方法返回 Date 对象自纪元以来的毫秒数。

例如,以下代码显示今年剩余的天数

js
const today = new Date();
const endYear = new Date(1995, 11, 31, 23, 59, 59, 999); // Set day and month
endYear.setFullYear(today.getFullYear()); // Set year to this year
const msPerDay = 24 * 60 * 60 * 1000; // Number of milliseconds per day
let daysLeft = (endYear.getTime() - today.getTime()) / msPerDay;
daysLeft = Math.round(daysLeft); // Returns days left in the year

此示例创建一个名为 todayDate 对象,其中包含今天的日期。然后它创建一个名为 endYearDate 对象并将年份设置为当前年份。然后,使用每天的毫秒数,它使用 getTime 计算 todayendYear 之间的天数,并四舍五入到整天的天数。

parse 方法对于将日期字符串中的值分配给现有的 Date 对象很有用。例如,以下代码使用 parsesetTime 将日期值分配给 ipoDate 对象

js
const ipoDate = new Date();
ipoDate.setTime(Date.parse("Aug 9, 1995"));

示例

在以下示例中,函数 JSClock() 以数字时钟的格式返回时间。

js
function JSClock() {
  const time = new Date();
  const hour = time.getHours();
  const minute = time.getMinutes();
  const second = time.getSeconds();
  let temp = String(hour % 12);
  if (temp === "0") {
    temp = "12";
  }
  temp += (minute < 10 ? ":0" : ":") + minute;
  temp += (second < 10 ? ":0" : ":") + second;
  temp += hour >= 12 ? " P.M." : " A.M.";
  return temp;
}

JSClock 函数首先创建一个名为 time 的新 Date 对象;由于没有给出参数,因此 time 使用当前日期和时间创建。然后,对 getHoursgetMinutesgetSeconds 方法的调用将当前小时、分钟和秒的值分别分配给 hourminutesecond

以下语句基于时间构建一个字符串值。第一条语句创建一个变量 temp。它的值为 hour % 12,即 12 小时制中的 hour。然后,如果小时为 0,则将其重新分配为 12,以便将午夜和中午显示为 12:00 而不是 0:00

下一条语句将 minute 值附加到 temp。如果 minute 的值小于 10,则条件表达式添加一个带有前导零的字符串;否则,它添加一个带有分隔符冒号的字符串。然后,一条语句以相同的方式将秒值附加到 temp

最后,一个条件表达式在 hour 大于或等于 12 时将 "P.M." 附加到 temp;否则,它将 "A.M." 附加到 temp