JavaScript的===和==

原文:Triple Equals vs Double Equals in JavaScript

何时使用==,何时使用===,经常会导致开发者困惑不已。简单的版本:除了一个小小的例外,应该一直使用===

在JavaScript中,技术上有4种不同的方式可以比较两个值是否相等。最常用的2种是==运算符和===运算符,也可以叫做宽松相等和严格相等

=== 严格相等

2个值xy,JavaScript这样检查是否x === y

  1. 检查xy的类型。如果是不同类型,返回false。
  2. 如果xy是数值,先检查xy是不是NaN,其中一个是NaN则返回false。如果xy+0-0,返回true。其他情况,检查它们是否是相同数值。
  3. 如果xy都是null或都是undefined,返回true
  4. 如果xy都是Boolean、或String、或Symbol,根据值进行比较。
  5. 如果xy都是对象,只有在它们指向相同对象时才返回true

简言之,===最重要的细节是:

  1. 没有隐式的类型转换。===不会调用valueOf()或尝试用其他方式把对象转为原始类型。
  2. 没有任何值=== NaN。不要用===检查NaN,用Number.isNaN()
  3. 对象比较是按引用比较——两个不同的对象,包含完全相同的键值对,但===认为它们是不相等的。
1
2
3
4
const obj1 = { answer: 42 };
const obj2 = { answer: 42 };

obj1 === obj2; // false

宽松相等 ==

==运算符使用更复杂的抽象相等比较算法,来比较xy是否相等。总结如下:

  1. 如果xy是相同类型,检查x === y是否成立。
  2. 如果xy都是null或都是undefined,返回true。
  3. 如果x是数值而y是字符串,y转换为数值,然后用===比较。类似的,如果x是布尔值或字符串,而y是数值,则x转换为数值。
  4. 如果xy是布尔值,将另一个值转换为数值进行比较。
  5. 如果x是对象,而y是Symbol、或字符串、或数值,尝试用valueOf()函数将x转换为原始类型,然后用===进行比较。

宽松相等会造成很多著名的BUG场景

1
2
3
4
'    ' == 0; // true
' ' == false; // true
({ valueOf: () => 42 }) == 42; // true
({ valueOf: () => 0 }) == false; // true

一般来说,应该总是用===,而非==,除非你有确切的理由。==有一个简洁的用途:一次检查是否为nullundefined(所谓的空值):

1
2
3
4
5
// 只有在`v === null`或`v === undefined`才是true
v == null;

// 等价于
v === null || v === undefined;

v == null是检查v是否严格等于nullundefined的一种简便方法,如果你是一个熟练的JavaScript开发者,这样使用是没问题的。但是,一直使用===也是没错的,而且更安全。

ESLint有一条规则,除非右侧是null,否则禁用==