我们都知道JavaScript有==
(相等)和===
(严格相等)运算符进行比较。但究竟有何区别,更重要的是,在幕后发生了什么?让我们深入了解!
区别
==
是一种强制转换比较。这里的强制转换意味着虚拟机(VM
)试图强制两侧变成相同的类型,然后再比较它们是否相等。以下是一些被自动强制转换成相等的示例:
"1" == 1 // true
1 == "1" // true
true == 1 // true
1 == true // true
[1] == 1 // true
1 == [1] // true
强制转换是对称的,如果a == b
是 true
,则b == a
也是true
。另一方面,===
只有在两个操作数完全相同(除了 Number.NaN
之外)时才为true
。因此,以上示例中的任何一个都不会在 ===
中为true
。
强制转换规则
实际规则很复杂(这本身就是不使用 ==
的原因之一)。但为了展示规则有多复杂,我尝试使用 ===
实现了==
。
function doubleEqual(a, b) {
if (typeof a === typeof b) return a === b;
if (wantsCoercion(a) && isCoercable(b)) {
b = b.valueOf();
} else if (wantsCoercion(b) && isCoercable(a)) {
const temp = a.valueOf();
a = b;
b = temp;
}
if (a === b) return true;
switch (typeof a) {
case "string":
if (b === true) return a === "1" || a === 1;
if (b === false) return a === "0" || a === 0 || a == "";
if (a === "" && b === 0) return true;
return a === String(b);
case "boolean":
if (a === true) return b === 1 || String(b) === "1";
else return b === false || String(b) === "0" || String(b) === "";
case "number":
if (a === 0 && b === false) return true;
if (a === 1 && b === true) return true;
return a === Number(String(b));
case "undefined":
return b === undefined || b === null;
case "object":
if (a === null) return b === null || b === undefined;
default:
return false;
}
}
function wantsCoercion(value) {
const type = typeof value;
return type === "string" || type === "number" || type === "boolean";
}
function isCoercable(value) {
return value !== null && typeof value == "object";
}
哇,这太复杂了,我甚至不确定它是否正确!
有趣的是,如果操作数之一是对象,虚拟机会调用.valueOf()
来允许对象强制转换为原始类型。
强制转换的性能成本
好吧,那个实现很复杂。那么==
比===
慢多少?看看这个图表。 (查看此处的基准测试)
首先让我们谈谈数字数组。当虚拟机注意到数组是纯整数时,它会将它们存储在一个称为 PACKED_SMI_ELEMENTS
的特殊数组中。在这种情况下,虚拟机知道可以将 ==
视为===
,性能是一样的。这解释了为什么在数字的情况下==
和 ===
没有区别。但一旦数组包含除了数字以外的东西,对于 ==
来说情况就开始变得糟糕了。
对于字符串,==
的性能降低了 50%,而且只会变得更糟。
字符串在虚拟机中是特殊的,但一旦涉及到对象,我们就会慢 4 倍。看看混合列,减速现在是 4 倍!
但情况变得更糟。对象可以定义 valueOf
来将自身强制转换为原始值。所以现在虚拟机必须调用该方法。当然,定位对象上的属性是受内联缓存控制的。内联缓存是属性读取的快速路径,但是一个多态读取可能会体验到 60 倍的减速,这可能会使情况变得更糟。如图所示,作为最坏情况(objectsMega
)的情况下,==
比 ===
慢 15 倍!
继续使用 == 的理由?
现在,===
非常快!因此,即使使用==
将速度降低15倍,在大多数应用程序中也不会产生太大的影响。然而,我很难想出为什么应该使用==
而不是===
的任何理由。强制转换规则很复杂,而且它是性能上的一大障碍,所以在使用==
之前请三思。
网友评论