JavaScript 悟道
coderljw 2024-10-13 大约 2 分钟
# 1. 数值
- JavaScript 的浮点数并不是 IEEE 754 标准的完全实现。Java 的浮点数实现用的是 IEEE 754 的一个子集,而 JavaScript 用的则是该子集的子集,所有 JavaScript 的 number 类型与 Java 的 double 类型非常相似,都是 64 位的浮点数类型。一个 number 类型包含 1 位符号位(sign)、11 位指数位以及 53 位有效位数。有些神奇的编码能将 65 位数据装进 64 位内存中。
# 2. 运算符
- JavaScript 并不存在取模运算,只有取余运算。取余运算的正负取决于被除数,而取模则取决于除数(知乎 (opens new window))。
4 / -3 = -1.333...3..3 // 不能整除
// 取模商为 -2(向负无穷取整),取余商为 -1(向0取整)
r = 4 - (-2 * -3) = 2
r = 4 - (-1 * -3) = 1
// 取模结果为 2,取余结果为 1
1
2
3
4
5
6
2
3
4
5
6
# 3. “怪兽” 来了
function deconstruct(number) {
// 数值 = 符号位 * 系数 * (2 ** 指数)
let sign = 1
let coefficient = number
let exponent = 0
if (coefficient < 0) {
coefficient = -coefficient
sign = -1
}
// 磨光系数(Number.isFinite(value)函数会在值为NaN、Infinity或者-Infinity的时候返回false)
if (Number.isFinite(number) && number !== 0) {
// -1128 就是 Number.MIN_VALUE 的指数减去有效位数再减去奖励位的结果
exponent = -1128
let reduction = coefficient
while (reduction !== 0) {
exponent += 1
reduction /= 2
}
// 磨光指数
reduction = exponent
while (reduction > 0) {
coefficient /= 2
reduction -= 1
}
while (reduction < 0) {
coefficient *= 2
reduction += 1
}
}
return {
sign,
coefficient,
exponent,
number,
}
}
// 计算值(不要用JS引擎,用科学计算器)
const scienceValue = sign * coefficient * 2 ** exponent,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# 4. 高精度整数、浮点数、有理数
- 硬核,啃不动,先打入冷宫!
# 5. 关系运算符
除非你肯定值得大小在安全整数范围内,否则不要通过 === 的条件判断来结束循环。即使在安全整数范围内,我也还是推荐使用 >=、<=、>、<。
答应我,永远不要用这两个运算符(== 和 !=)。答应我,务必使用 === 和 !==(答应他!答应他!)。
# 6. 非
- 德·摩根定律可用于简化逻辑表达式。
!(p && q) === !p || !q
!(p || q) === !p && !q
1
2
2
# 7. 数组
数组有一个神奇的 length 属性。该属性并不是指数组中元素的数量,而是指数组元素的最高序数加 1。
sort 方法有一个比较严重的问题,那就是缺乏稳定性。在比较两个相等值的时候(比较函数会返回 0),如果排序方法将这两个值排在它们原来的位置上,则可以说该排序方法是稳定的。
想象一下,你正在对姓名进行排序:先判断姓的顺序,若姓相同再判断名的顺序。如果 sort 方法稳定,我们就可以这么做:先对姓排一遍序,结束后再对名排一遍序。可惜的是 JavaScript 并不具备该稳定性,第二遍排序会把第一遍已排好的姓打乱。