你不知道的JavaScript值比较

337 阅读3分钟

ES2015中有四种相等算法:

  • 抽象(非严格)相等比较 (==)
  • 严格相等比较 (===): 用于  Array.prototype.indexOfArray.prototype.lastIndexOf, 和 case-matching
  • 同值零: 用于 %TypedArray% 和 ArrayBuffer 构造函数、以及MapSet操作, 并将用于 ES2016/ES7 中的String.prototype.includes
  • 同值: 用于所有其他地方

JavaScript提供三种不同的值比较操作:

  • 严格相等比较 (也被称作"strict equality", "identity", "triple equals"),使用 === ,
  • 抽象相等比较 ("loose equality","double equals") ,使用 ==
  • 以及 Object.is (ECMAScript 2015/ ES6 新特性)

理解相等比较的模型

1649234682(1).png

什么时候使用 Object.is 或是三等

总的来说,除了对待NaN的方式,Object.is唯一让人感兴趣的,是当你需要一些元编程方案时,它对待0的特殊方式,特别是关于属性描述器,即你的工作需要去镜像Object.defineProperty的一些特性时。如果你的工作不需要这些,那你应该避免使用Object.is,使用===来代替。即使你需要比较两个NaN使其结果为true,总的来说编写使用NaN 检查的特例函数(用旧版本ECMAScript的isNaN方法)也会比想出一些计算方法让Object.is不影响不同符号的0的比较更容易些。

这里是一个会区别对待-0和+0的内置方法和操作符不完全列表:

  • - (一元负)

    显而易见,对0一元负操作得到``-0。但表达式的抽象化可能在你没有意识到得情况下导致-0延续传播。例如当考虑下例时:

    let stoppingForce = obj.mass * -obj.velocity
    

    Copy to Clipboard

    如果obj.velocity0 (或计算结果为0), 一个-0就在上处产生并被赋值为stoppingForce的值.

  • Math.atan2Math.ceilMath.powMath.round

    即使传入的参数中没有-0,这些方法的返回值都有可能是-0。例如当用 Math.pow计算-Infinity的任何负奇指数的幂都会得到-0。详情请参见这些方法各自的文档。

  • Math.floorMath.maxMath.minMath.sinMath.sqrtMath.tan

    当传入参数中有-0时,这些方法也可能返回-0。例如, Math.min(-0, +0) 得出 -0。详情请参见这些方法各自的文档。

  • ~<<>>

    这些操作符内部都使用了ToInt32算法。因为内部32位整数类型只有一个0(没有符号区别),-0的符号在反操作后并不会保留下来。例如Object.is(~~(-0), -0)Object.is(-0 << 2 >> 2, -0) 都会得到false.

在未考虑0的符号的情况下依赖于Object.is是危险的。当然,如果本意就是区分-0和+0的话,Object.is能按照期望完成工作。

文章来源: MDN-JavaScript 中的相等性判断