Skip to Content

面试导航 - 程序员面试题库大全 | 前端后端面试真题 | 面试

Javascript== 和 === 的区别

在 JavaScript 中,===== 是两种常用的比较运算符,它们用于判断两个值是否相等,但它们的行为有显著不同。了解它们的区别非常重要,以便避免不必要的错误和困惑。

== 看似做的更多,因为它需要进行强制类型转换,但实际上这种转换的开销非常小,只是微秒级的差异(百万分之一秒)。因此,通常我们并不需要为性能担忧。

如果两个值的类型不同,且需要强制类型转换,使用 == 是合适的。如果类型相同,使用 === 会更直观、安全,且不涉及类型转换。

抽象相等

ES5 规范 11.9.3 节的 抽象相等比较算法 定义了 == 运算符的行为,在使用 == 比较的时候,当使用 == 对 x 和 y 进行比较时,会返回 true或者 false的值,它们主要遵循以下的规则:

  1. 如果 xy 的类型相同:

    1. 如果 xundefined,返回 true;

    2. 如果 xnull,返回 true;

    3. 如果 xNumber 类型,则:

      1. 如果 xNaN,则返回 false;

      2. 如果 yNaN,则返回 false;

      3. 如果 xy 相同,则返回 true;

      4. 如果 x-0y+0,则返回 true;

      5. 如果 y-0x+0,则返回 true;

      6. 其他情况返回 false;

    4. 如果 xstring 类型,并且 xy 的完全相同的值(长度相同,对应位置的字符相同),则返回 true;

    5. 如果 xBoolean 类型,并且 xy 都是 true 或者 false,则返回 true,否则返回 false;

    6. 如果 xy 引用同一个对象,则返回 true,否则返回 false;

  2. 如果 xnullyundefined,则返回 true;

  3. 如果 ynullxundefined,则返回 true;

  4. 如果 xnumber 类型且 ystring 类型,则返回 x == ToNumber(y)的比较结果;

  5. 如果 ynumber 类型且 xstring 类型,则返回 y == ToNumber(x)的比较结果;

  6. 如果 xboolean 类型,返回 ToNumber(x) == y的比较结果;

  7. 如果 yboolean 类型,返回 ToNumber(y) == x的比较结果;

  8. 如果 xstring 类型或者 number 类型,并且 yobject 类型,返回 x == ToPrimitive(y) 的比较结果;

  9. 如果 ystring 类型或者 number 类型,并且 xobject 类型,返回 y == ToPrimitive(x) 的比较结果;

  10. 否则返回 false;

抽象相等的这些规则正是隐式强制类型转换不受人喜爱的原因,但是认真一看规则,其实简单明了。

字符串和数字之间的相等比较

const a = 77; const b = '77'; console.log(a === b); // false console.log(a == b); // true

因为没强制类型转换,所以 a === bfalse77"77" 不相等。

a == b是宽松相等,即如果两个值的类型不同,则对其中之一或者两者都进行强制类型转换,具体怎么转换的,请看定义,它们是这样的:

  1. 如果 xnumber 类型且 ystring 类型,则返回 x == ToNumber(y)的比较结果;

  2. 如果 ynumber 类型且 xstring 类型,则返回 y == ToNumber(x)的比较结果;

也就是说, a == b 在代码中实际上是这样的行为:

const a = 77; const b = '77'; console.log(a === Number(b)); // true

其他类型和布尔值之间的相等比较

==最容易出错的是一个地方是 truefalse于其他类型之间的相等比较,例如:

const a = '77'; const b = true; console.log(a == b); // false

我们都知道 "77" 是一个真值,为什么 == 的结果不是 true呢?因为规范是这样定义的:

  1. 如果 xboolean 类型,返回 ToNumber(x) == y的比较结果;

  2. 如果 yboolean 类型,返回 ToNumber(y) == x的比较结果;

首先 bboolean 类型,所以 ToNumber(b)b 的类型强制转换为 1,变成 1 == '77',二者的类型仍然不同,"77" 根据规则被强制类型转换为 77,最后变成 1 == 77,所以结果输出为 false;

null 和 undefined 之间的相等比较

nullundefined 之间的 == 也设计隐式强制类型转换,ES5规范 是这样规定的:

  1. 如果 xnullyundefined,则返回 true;
  2. 如果 ynullxundefined,则返回 true;

==nullundefined 相等(它们也与其自身相等),除此之外其他值都不和它们两个相等。

这也就是说,在==nullundefined 是一回事,可以相互进行隐式强制类型转换:

var a = null; var b = undefined; console.log(a == b); // true console.log(a == null); // true console.log(b == null); // true console.log(a == false); // false console.log(b == false); // false console.log(a == ''); // false console.log(b == ''); // false console.log(a == 0); // false console.log(b == 0); // false

null he undefined 之间的强制类型转换是安全可靠的,上例中除 nullundefined 以外的其他值均为无法返回 true 的结果。

对象和非对象之间的相等比较

对于对象和基本类型之间的相等比较,ES5规范是遵循这样的规则:

  1. 如果 xstring 类型或者 number 类型,并且 yobject 类型,返回 x == ToPrimitive(y) 的比较结果;
  2. 如果 ystring 类型或者 number 类型,并且 xobject 类型,返回 y == ToPrimitive(x) 的比较结果;
  • 例如:
var a = 77; var b = [77]; console.log(a == b); // true

[77] 首先调用了 ToPrimitive 抽象操作,返回 "77",变成 "77" == 77,然后又变成 77 == 77,最后二者相等。其中代码的转变过程是以下的形式:

var a = 77; var b = [77]; console.log(a === Number(b.toString())); // true

我们再来看一个 string 类型和 object 类型的例子:

var a = 'abc'; var b = Object(a); console.log(a === b); // false console.log(a == b); // b

a == b 结果为 true,因为 b 通过 TOPrimitive 进行强制类型转换(拆封),并返回基本数据类型值 "abc",与 a 相等。

但是规则总有特例,原因是 == 算法中其他优先级更高的原则。例如:

var foo = null; var bar = Object(foo); console.log(foo == bar); // false var a = undefined; var b = Object(a); console.log(a == b); // false var c = NaN; var d = Object(NaN); console.log(c == d); // false

因为没有对应的封装对象,所以 nullundefined 不能够被封装和 Object() 均返回一个空对象,你也可以理解成空对象调用 toString() 方法返回的值是 "[object Object]",不等于 nullundefined

NaN能够被封装为数字封装对象,但拆封之后 NaN == NaN 返回 false,因为 NaN 不等于 NaN

希望你永远不会用到

在上面的讲解中,我们已经介绍了 == 中的隐式强制类型转换,现在来看一下那些需要特别注意和避免的比较少见的情况。

返回其他的数字

首先来看看更改内置原生模型会导致哪些奇怪的结果:

Number.prototype.valueOf = function () { return 3; }; console.log(new Number(77) == 3); // true

2 == 3 不会有这样的问题,因为 23 都是数字基本类型值,不会调用 Number.prototype.valueOf() 方法。而 Number(2) 涉及 ToPrimitive 强制类型转换,因此会调用 valueOf()

再来看一种情况,这个你可能面试题里经常看到,a == 2 && a == 5 在什么情况下为 true?

if (a == 2 && a == 3) { // ... }

你也许觉得不可能,因为 a 不会同时等于 23 。但 同时似乎说的不对,因为 a == 2a == 3 之前执行。如果让 a..valueOf() 每次调用都产生副作用,比如第一次返回 2,第二次返回 3,就会出现这样的情况。这实现起来很简单:

const a = { value: 1 }; a.valueOf = function () { return this.value++; }; if (a == 1 && a == 2 && a == 3) { console.log("嗨,没想到吧,意不意外,惊不惊喜"); // 这里正常输出了 }

假值的相等比较

==中的隐式强制类型转换最为让人不满的地方是假值的相等比较下面分别列出了常规和非常规的情况:

console.log('0' == null); // false console.log('0' == undefined); // false console.log('0' == false); // true console.log('0' == NaN); // false console.log('0' == 0); // true console.log('0' == ''); // false console.log(false == null); // false console.log(false == undefined); // false console.log(false == NaN); // false console.log(false == 0); // true console.log(false == ''); // true console.log(false == []); // true console.log(false == {}); // false console.log('' == null); // false console.log('' == undefined); // false console.log('' == NaN); // false console.log('' == 0); // true console.log('' == []); // true console.log('' == {}); // false console.log(0 == null); // false console.log(0 == undefined); // false console.log(0 == NaN); // false console.log(0 == []); // true console.log(0 == {}); // false

接下来我们挑一些有代表性的例子来具体讲解一下:

  1. 其中这些例子中最好辨认的是在 == 比较中,NaN 与任何值相比都是 falseNaN也是;

  2. "0" == false 中会对 false 先转换成数字类型,即 0,变成了 "0" == 0,再对 "0" 转换,最终变成了 0 == 0,所以输出为 true;

  3. false == []中,会对 []进行 ToPrimitive 类型转换,转换成原始类型 "",这时候变成了 false == "",所以输出结果为 true,至于为什么是 true,我想你应该懂了吧

接下来还有一些例子:

console.log([] == ![]); // true console.log('' == [null]); // true console.log('' == [undefined]); // true

喔喔喔,这是什么,怎么都输出了 true,它们到底都干了啥?

在第一个中, ! 运算符对 [] 做了取反操作,因为 [] 为真值,而 ![] 也就变成了 false了,所以 [] == ![] 变成了 [] == false,前面我们有讲过这个比较的结果,所以最后的结果也很正常了。

在第二、三个例子中,[null].toString()最后返回 "",而难懂的是 String(null) 返回的是 "null",而 String([Null]) 去返回的是 "",这就是难懂的地方,这也是 js 令人深入理解的原因。

所以 ===== 选择哪一个取决于是否允许在相等比较中发生强制类型转换。

好了,本篇的内容讲解到此结束了,有什么不了解的可以在评论区留下你的疑问。

参考文章

最后更新于:
Copyright © 2025Moment版权所有粤ICP备2025376666