原文地址:www.builder.io/blog/double…
作者 MIŠKO HEVERY
前言
我们都知道 JavaScript 有 == (相等)和 === (严格相等)运算符用于比较。但究竟有什么区别,更重要的是,幕后发生了什么?让我们开始吧!
不同点
== 是强制比较。是指VM试图强制两端为同一类型,然后看是否相等。以下是自动强制相等的一些示例:
"1" == 1 // true
1 == "1" // true
true == 1 // true
1 == true // true
[1] == 1 // true
1 == [1] // true
强制转换是对称的,如果 a == b 为真,则 b == a 也为真。
=== 仅当两个变量完全相同时才为真(Number.NaN 除外)。
上面的例子都不适合 ===。
比较规则
实际规则很复杂(这本身就是不使用 == 的原因)。但是为了说明规则有多么复杂,我只使用 === 实现了 == 。
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;
}
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";
}
这很复杂,我甚至不确定它是否正确!也许其他人知道更简单的算法,但这是我能做的最好的。
有趣的是,如果其中一个操作数是一个对象,则 VM 调用 .valueOf() 以允许该对象将自身强制转换为基本类型。
性能开销
那么 == 比 == 性能开销多多少呢?查看此图表。
越高越快(每秒操作次数越多)。
数字类型
首先让我们谈谈数字数组。当 VM 注意到数组是纯整数时,它会将它们存储在一个称为 PACKED_SMI_ELEMENTS 的特殊数组中。在这种情况下,VM 知道将 == 视为 === 是安全的并且性能是相同的。这解释了为什么在数字的情况下 == 和 === 之间没有区别。
但是一旦数组包含数字以外的内容, == 的性能就开始下降了。
字符串等其他类型
使用 strings 时, == 的性能比 === 降低了 50%,甚至 50% 都不到。
字符串在 VM 中很特殊,但是一旦涉及到对象,我们就会慢 4 倍。查看 混合 列,减速现在慢了 4 倍!
对象可以定义 valueOf 以将其自身强制转换为基元。所以现在 VM 必须调用该方法。当然,定位对象的属性受内联缓存的影响。内联缓存是属性读取的快速路径,但巨型读取可能会减速 60 倍,这会使情况变得更糟。如图所示,作为最坏情况 ( objectsMega ) 的情况, == 比 === 慢 15 倍!
什么时候使用 ==
以现在电脑的运行速度来看, === 非常快!即使 === 减速 15 倍,在大多数应用程序中也不会产生太大差异。
尽管如此,我还是很难想出为什么应该使用 == 而不是 === 的任何原因。强制转换规则很复杂,而且在多数的编译器中、ESlink中会出现警告提醒。