数字和日期
本章介绍了用于处理和执行数字和日期计算的JavaScript概念、对象和函数。这包括使用以各种进制(包括十进制、二进制和十六进制)编写的数字,以及使用全局Math
对象对数字执行各种数学运算。
数字
在JavaScript中,数字以双精度64位二进制格式IEEE 754(即,介于±2^−1022和±2^+1023之间的数字,或大约±10^−308到±10^+308,数值精度为53位)实现。最多±2^53 − 1的整数值可以精确表示。
除了能够表示浮点数之外,number类型还有三个符号值:Infinity
、-Infinity
和NaN
(非数字)。
另请参阅JavaScript数据类型和结构,以了解JavaScript中其他基本类型的上下文。
您可以使用四种类型的数字字面量:十进制、二进制、八进制和十六进制。
十进制数
1234567890
42
十进制字面量可以以零(0
)开头,后跟另一个十进制数字,但如果前导0
之后的数字都小于8,则该数字将被解释为八进制数。这被认为是遗留语法,并且以0
为前缀的数字字面量(无论解释为八进制还是十进制),都会在严格模式中导致语法错误——因此,请改用0o
前缀。
0888 // 888 parsed as decimal
0777 // parsed as octal, 511 in decimal
二进制数
二进制数语法使用前导零,后跟小写或大写拉丁字母“B”(0b
或0B
)。如果0b
之后的数字不是0或1,则会抛出以下SyntaxError
:“0b之后缺少二进制数字”。
0b10000000000000000000000000000000 // 2147483648
0b01111111100000000000000000000000 // 2139095040
0B00000000011111111111111111111111 // 8388607
八进制数
八进制数的标准语法是以0o
为前缀。例如
0O755 // 493
0o644 // 420
八进制数还有一个遗留语法——通过以零为前缀:0644 === 420
和"\045" === "%"
。如果0
之后的数字超出0到7的范围,则该数字将被解释为十进制数。
const n = 0755; // 493
const m = 0644; // 420
严格模式禁止此八进制语法。
十六进制数
十六进制数语法使用前导零,后跟小写或大写拉丁字母“X”(0x
或0X
)。如果0x之后的数字超出范围(0123456789ABCDEF),则会抛出以下SyntaxError
:“标识符紧跟在数字字面量之后开始”。
0xFFFFFFFFFFFFFFFFF // 295147905179352830000
0x123456789ABCDEF // 81985529216486900
0XA // 10
指数运算
0e-5 // 0
0e+5 // 0
5e1 // 50
175e-2 // 1.75
1e3 // 1000
1e-3 // 0.001
1E3 // 1000
Number 对象
内置的Number
对象具有数值常量的属性,例如最大值、非数字和无穷大。您不能更改这些属性的值,您可以按以下方式使用它们
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…),您将在应用程序中使用它,如下所示
Math.PI;
类似地,标准数学函数是Math
的方法。这些包括三角函数、对数函数、指数函数和其他函数。例如,如果您想使用三角函数正弦,您可以编写
Math.sin(1.56);
请注意,Math
的所有三角方法都以弧度为单位接受参数。
下表总结了Math
对象的方法。
方法 | 描述 |
---|---|
abs() |
绝对值 |
sin() ,cos() ,tan() |
标准三角函数;参数以弧度为单位。 |
asin() ,acos() ,atan() ,atan2() |
反三角函数;返回值以弧度为单位。 |
sinh() ,cosh() ,tanh() |
双曲函数;参数为双曲角。 |
asinh() ,acosh() ,atanh() |
反双曲函数;返回值为双曲角。 |
指数和对数函数。 | |
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
为后缀的整数字面量
const b1 = 123n;
// Can be arbitrarily large.
const b2 = -1234567890987654321n;
BigInt 也可以使用 BigInt
构造函数从数值或字符串值构建。
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 只是一个任意长的位序列,它编码一个整数。您可以安全地执行任何算术运算,而不会丢失精度或溢出/下溢。
const integer = 12 ** 34; // 4.9222352429520264e+36; only has limited precision
const bigint = 12n ** 34n; // 4922235242952026704037113243122008064n
与数字相比,BigInt 值在表示大整数时具有更高的精度;但是,它们不能表示浮点数。例如,除法将四舍五入为零
const bigintDiv = 5n / 2n; // 2n, because there's no 2.5 in BigInt
Math
函数不能用于 BigInt 值。有一个 开放提案 来重载某些 Math
函数(如 Math.max()
)以允许 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
对象
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 年以来的年份
例如,假设您定义以下日期
const xmas95 = new Date("1995-12-25");
然后 xmas95.getMonth()
返回 11,而 xmas95.getFullYear()
返回 1995。
getTime
和 setTime
方法对于比较日期很有用。getTime
方法返回 Date
对象自纪元以来的毫秒数。
例如,以下代码显示今年剩余的天数
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
此示例创建一个名为 today
的 Date
对象,其中包含今天的日期。然后它创建一个名为 endYear
的 Date
对象并将年份设置为当前年份。然后,使用每天的毫秒数,它使用 getTime
计算 today
和 endYear
之间的天数,并四舍五入到整天的天数。
parse
方法对于将日期字符串中的值分配给现有的 Date
对象很有用。例如,以下代码使用 parse
和 setTime
将日期值分配给 ipoDate
对象
const ipoDate = new Date();
ipoDate.setTime(Date.parse("Aug 9, 1995"));
示例
在以下示例中,函数 JSClock()
以数字时钟的格式返回时间。
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
使用当前日期和时间创建。然后,对 getHours
、getMinutes
和 getSeconds
方法的调用将当前小时、分钟和秒的值分别分配给 hour
、minute
和 second
。
以下语句基于时间构建一个字符串值。第一条语句创建一个变量 temp
。它的值为 hour % 12
,即 12 小时制中的 hour
。然后,如果小时为 0
,则将其重新分配为 12
,以便将午夜和中午显示为 12:00
而不是 0:00
。
下一条语句将 minute
值附加到 temp
。如果 minute
的值小于 10,则条件表达式添加一个带有前导零的字符串;否则,它添加一个带有分隔符冒号的字符串。然后,一条语句以相同的方式将秒值附加到 temp
。
最后,一个条件表达式在 hour
大于或等于 12 时将 "P.M." 附加到 temp
;否则,它将 "A.M." 附加到 temp
。