双等号(==)和三等号(===)在JavaScript中的性能差异

51

在JavaScript中,使用双等号(==)和三等号(===)是否会对性能产生影响?

例如:if (foo == bar)if (foo === bar)的区别。


22
你永远都不会注意到这件事,继续前进吧。 - Lightness Races in Orbit
2
它们有不同的用途,而“更高的性能”不是其中之一。这不是问题,当您想要获得它们提供的功能时,请使用它们。 - user229044
2
推荐阅读:你不知道的JS - Jon Surrell
5
由于这仍是谷歌上这个问题的最佳搜索结果,而且我没有看到任何测试结果,所以我会加上一个。进行了4次小型Node.js测试的平均结果(每个操作符共进行了800亿次测试),发现=====快0.0027%。即使差异真的那么大,也比眨眼或普通人大脑反应对普通刺激所需的时间快约10,000倍。为了支持“轻盈环绕比赛”的评论,我想不出有哪种情况下可能会在两者之间注意到速度差异。 - GreenRaccoon23
1
@JonSurrell 谢谢分享这个有趣的链接 :) 五年之后,地址已更改 - massic80
更新推荐阅读链接:You Don't Know JS - Jon Surrell
6个回答

45
  • 如果比较的类型相同,它们就是完全相同的。也就是说,它们使用完全相同的算法

  • 如果类型不同,则性能无关紧要。你需要类型强制转换,或者不需要。如果不需要,不要使用==,因为你得到的结果可能出乎意料。


39

严格比较符 (===) 总体上始终会稍微快一些,但 差异通常是可以忽略不计的

如果您确定比较中不需要类型转换,那么优先选择 === 是有意义的。它始终至少和 == 一样快。


3
有趣的是,对我来说==在FF7上两次测试中都比===快。我同意===应该更快,但测试结果表明相反(可能是JavaScript引擎/ CPU负载方面的差异,谁知道呢)。 - Nightfirecat
@Nightfirecat:很有趣。你是在比较变量还是字面值? - Dave Ward
2
如果操作数的类型相同,则=====被指定为执行完全相同的步骤。 - Tim Down
为什么你说它稍微快一点。根据你的jsperf链接,当它不是相同类型时,它会快10倍。 - Ofir Meguri
如果类型不同,则 == 可能会显着变慢。例如:x =''; y = 0; (x == y) 执行类型转换,导致减速。如果您知道类型可能不同,并且非常关注性能,则使用 === 可能会更快一些。(但是如果您自己进行类型转换,则显然不会有性能提升。) - Drakinite
显示剩余2条评论

17

编辑: 参考以下由Axel Rauschmayer博士提供的按规范解释 http://www.2ality.com/2011/06/javascript-equality.html 真的很好的写作。

===(严格相等):仅认为具有相同类型的值相等。

  1. undefined === undefined,null === null,
  2. NaN === 除本身外的任何值,
  3. 原始值 [Number|String|Boolean] === 原始值相等,
  4. 对自身(+0 === -0)
  5. 两个对象[Array|Object|Function] === 仅适用于自身(完全相同实体)

==(宽松相等)

  1. 如果两个值具有相同的类型:使用 === 进行比较。
  2. undefined == null
  3. 数字和字符串:将字符串转换为数字并进行比较
  4. 布尔值和非布尔值 => 将非布尔值转换为数字并进行比较
  5. 字符串或数字 => 对象:将对象转换为原始值并进行比较。
在所有现代JavaScript环境中,它们的实现完全不同。简单来说,==通过将给定变量转换为基元(字符串、数字、布尔值)来测试相似性。===测试严格的相同性,这意味着确切相同的对象或基元值而不进行转换。
如果你执行objOne == objTwo,实际发生的是[[EQUALS]].call(objOne.valueOf(), objTwo.valueOf()) valueOf的解析可能有些复杂,会在JS中公开的函数和内部引擎之间反弹。可以说,比较将始终以两个值被强制转换为基元或抛出错误结束。 编辑:EQUALS实际上首先尝试STRICT_EQUALS,这会预先处理其余过程。
有趣的一点是,valueOf(及其伴侣toString)是可重写的。在Chrome中运行此代码片段(我认为任何Webkit都可以,不确定JSC和V8是否共享此信息),它会让你大吃一惊:
var actions = [];
var overload = {
  valueOf: function(){
    var caller = arguments.callee.caller;
    actions.push({
      operation: caller.name,
      left: caller.arguments[0] === this ? "unknown" : this,
      right: caller.arguments[0]
    });
    return Object.prototype.toString.call(this);
  }
};
overload.toString = overload.valueOf;
overload == 10;
overload === 10;
overload * 10;
10 / overload;
overload in window;
-overload;
+overload;
overload < 5;
overload > 5;
[][overload];
overload == overload;
console.log(actions);

输出:

[ { operation: 'EQUALS',
    left: overload,
    right: 10 },
  { operation: 'MUL',
    left: overload,
    right: 10 },
  { operation: 'DIV',
    left: 'unknown',
    right: overload },
  { operation: 'IN',
    left: overload,
    right: DOMWindow },
  { operation: 'UNARY_MINUS',
    left: overload,
    right: undefined },
  { operation: 'TO_NUMBER',
    left: overload,
    right: undefined },
  { operation: 'COMPARE',
    left: overload,
    right: 5 },
  { operation: 'COMPARE',
    left: 'unknown',
    right: overload },
  { operation: 'ToString',
    left: 'unknown',
    right: overload } ]

===== 之间的差异本质上在于=== 不显示在那个列表中。它完全跳过了进入JavascriptLand 的旅程。当比较性能时,这样的冒险是昂贵的。

然而,您需要考虑引擎优化。对于大多数对象,引擎将能够削减大部分步骤并保持在NativeLand中,获得几乎相同的性能。但这并不是一项保证,如果有什么阻止引擎能够使用优化,例如您代码中的某些花哨的东西或覆盖内置函数或无数问题,那么您会立即看到性能结果。 === 强制执行。

=== 是Javascript中唯一不可变的东西。


你有证据吗? 因为当操作数类型相同时,=====被指定为完全相同的工作方式,所以我不相信JS环境会在这种情况下实现它们不同。 - Tim Down
你读完我第一句话后,有没有看到我发布的内容?我直接包含了V8的输出结果。简短回答:==首先调用===,在===为真的情况下差异可以忽略不计。除此之外,==在定义上必输。 - user748221
仅供记录,我上面提供的证据是我想出来的一种新方法,能够从任意JavaScript对象中正确定位内部JS引擎操作函数调用者和操作数,在所有当前使用V8或JavaScriptCore实现的情况下,我从未见过其他人使用过这种方法,直接实现了JS中的运算符重载,否则这是不可能的,目前也没有成功实现。 - user748221
我已经阅读了。抱歉,我应该更明确地指出缺失的证据是关于“所有现代JavaScript环境”的部分。暴露的V8内部很有趣,但valueOf()自ECMAScript 1(1997年)以来就存在,因此并不新颖。您没有回答我的观点,即当两个操作数类型相同时会发生什么。将operator == {}operator === {}添加到您的示例中,您会发现它们都没有出现在您的actions数组中。 - Tim Down
在我看来,这应该是正确答案。==会调用===,然后尝试强制转换以查看是否以某种其他方式相似。当您尝试比较标识时,如果不相等的对象,则===显然更快。 - Brian Arsuaga
@BrianArsuaga:如果对象是不同类型,那么===比较操作符才更快。 - Tim Down

4

由于性能方面的考虑,我认为 ===== 更具优势,因为 ===== 更加严格。

例如在 Chrome 控制台中尝试以下代码:

> 1 == '1'
  true
> 1 === '1'
  false
< p > < code > == 需要检查的内容比 < code > === 更多。 < /p >

1

从一些脆弱的测试来看,==似乎比===稍微快一点。

稍微快一点,我的意思是在执行数百万次测试的迭代中可以看到几毫秒的差异。你不可能需要性能提升,而是使用最适合手头任务的方法。

编辑:实际上,这似乎取决于你正在比较什么以及浏览器的实现。换句话说,不要担心它。


1
=== 在大多数情况下更快。虽然有些例外情况(你找到了一个),但是从代码实践/风格指南的角度来看,每次都应该选择 === - Raynos
4
“don't worry about it” 可以翻译为“不用担心”,“You can't possibly need the performance gain” 可以翻译为“你肯定不需要这种性能提升”。由于我不知道该用户的意图以及所有来这里问问题的用户的意图,因此无法提供更多信息。 - cdosborn
2
@cdosborn 哇,你好2011年。这个问题早于SO上的nodejs标签。是的,你是正确的。当时合理的假设是它在浏览器中,削减毫秒/百万次评估会是...浪费时间。 ~5年后情况发生了很大变化。 - Hamish

0

这取决于被比较的项目。由于 "===" 比 "==" 更严格,所以它应该比 "==" 更快地返回 false。然而,如果两个项目严格相等,"===" 应该比 "==" 花费更多时间,因为它必须检查更多的属性是否相等。


你有关于这个比较的任何来源吗?其他答案提到差异是可以忽略不计的。 - Nico Haase
就性能而言,差异基本可以忽略不计,但它确实存在。 - Joseph C
请进一步解释 - 它为什么存在?它真的可以忽略不计吗?最好基于事实编写答案,以便其他人可以从中学习。 - Nico Haase

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接