前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >你还在瞒着我偷偷使用强制相等

你还在瞒着我偷偷使用强制相等

原创
作者头像
前端修罗场
发布2023-05-25 21:33:22
1260
发布2023-05-25 21:33:22
举报
文章被收录于专栏:Web 技术Web 技术

我们都知道JavaScript有== (强制相等)和===(严格相等)运算符进行比较。但你可能不知道它们两个究竟有什么不同,并且更重要的是,在 js 引擎中使用它们的时候发生了什么?

前面我们提到 == 是强制比较。强制意味着 VM 试图将进行比较的双方强制为相同的类型然后查看它们是否相等。以下我们列举了一些自动被强制相等的例子:

代码语言:javascript
复制
"1" == 1 // true
1 == "1" // true
true == 1 // true
1 == true // true
[1] == 1 // true
1 == [1] // true

你要知道,强制是对称的,如果a == b为真,那么b == a也为真。另一方面,只有当两个操作数完全相同时===才为真(除了Number.NaN)。因此,上面的例子都真实的情况下都是假真 (即,在 === 的情况下是 false 的)。

为什么强制相等有这样的问题,这要归咎与强制相等的规则。

强制相等的规则

实际的规则很复杂(这也是不使用==的原因)。但是为了显示规则有多么复杂,我通过使用===实现了==,带大家看看强制相等的规则到底多复杂:

代码语言:javascript
复制
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 "?developer/article/2291538/undefined":
      return b === ?developer/article/2291538/undefined || b === null;
    case "object":
      if (a === null) return b === null || b === ?developer/article/2291538/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 知道将 == 处理为 === 是安全的,性能是相同的。这解释了为什么在数字的情况下,===== 之间没有区别。但是,一旦数组中包含了数字以外的内容,== 的情况就变得很糟糕了。

对于字符串,===== 的性能下降了 50%,看起来挺糟的是吧。

字符串在VM中是特殊的,但一旦我们涉及到对象,我们就慢了 4 倍。看看 mix 这栏,现在速度减慢了 4 倍!

但还有更糟的。对象可以定义 valueOf,这样在转换的时候可以将自己强制转换为原语。虽然在对象上定位属性可以通过内联缓存,内联缓存让属性读取变得快速,但在超大容量读取的情况下可能会经历 60 倍的减速,这可能会使情况更糟。如图中最坏情况(objectsMega)场景所示,===== 慢15 倍!

有其他使用 == 的理由吗

现在,=== 非常快! 因此,即使是使用 === 的15倍减速,在大多数应用程序中也不会有太大区别。尽管如此,我还是很难想出为什么要使用 == 而不是 === 的任何理由。强制规则很复杂,而且它存在一个性能瓶颈,所以在使用 == 之前请三思。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 强制相等的规则
  • 强制转换的成本
  • 有其他使用 == 的理由吗
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com