【每日面试题】== 和 === 的区别

288 阅读3分钟

宽松相等(==)和严格相等(===)都是用来判断两个值是否“相等”,但是它们又一个很重要的区别。

== 允许在相等比较中进行强制类型转换,而 === 不允许。

== 和 === 都会检查操作数的类型。区别在于操作数类型不同时它们的处理方式不同。

抽象相等

如果两个值的类型相同,就今比较它们是否相等。

console.log(42 == 42); // true
console.log("abc" == "abcd"); // false

注意

  • NaN 不等于 NaN
  • +0 等于 -0

对象(包括函数和数组)的宽松相等 ==。两个对象指向同一个值时,视为相等,不会发生强制类型转换。

var obj = {
	value: 1,
  toString: function(){
  	return obj.value;
  }
};
var str = obj;
console.log(str == obj); // true

var arr = [1, 2];
var arr2 = arr;
console.log(arr == arr2); // true

== 在比较两个不同类型时会发生隐式强制类型转换,会将其中之一或两者都转换为相同的类型后再进行比较。

宽松不想等 != 就是 == 的相反值,!== 同理。

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

var a = 42;
var b = '42';

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

// == 比较时,将 b 转化为 数字 42,再与 a 进行比较

转换定义:

  • 如果 Type(x) 是数字,Type(y) 是字符串,则返回 x == ToNumber(y) 的结果。
  • 如果 Type(x) 是字符串,Type(y) 是数字,则返回 ToNumber(x) == y 的结果。

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

var a = '42';
var b = true;

console.log(a == b); // false

// == 比较时,将 a 转换为数字 42, 将 b 转换为数字 1
// 42 == 1 结果为 false

转换定义:

  • 如果 Type(x) 是布尔类型,则返回 ToNumber(x) == y 的结果。
  • 如果 Type(y) 是布尔类型,则返回 x == ToNumber(y) 的结果。
// 所以我们在想要判断 a 为真值时可以这样操作

var a = '42'

if (a) {}

// 推荐
if (!!a) {}

if (Boonlean(a)) {}

null 和 undefined 之间的相等比较。

转换定义:

  • 如果 x 为 null,y 为 undefined,则结果为 true。
  • 如果 x 为 undefined,y 为 null,则结果为 true。

在 == 中,null 和 endefined 相等(它们也和自身相等), 初次之外其他值都不存在这种情况。

var a = null;
var b;

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 和 undefined 之间的强制类型转换是安全可靠的。例子中除 null 和 undefined 以外的其他值均无法得到 true 的结果。

对象和非对象之间的比较。

关于对象(对象 / 函数 / 数组)和标量基本类型(字符串 / 数字 / 布尔值)之间相比较

转换定义:

  • 如果 Type(x) 是字符串或数字,Type(y) 是对象,则返回 x == ToPromitive(y) 的结果。
  • 如果 Type(x) 是对象,Type(y) 是字符串或数字,则返回 ToPromitive(x) == y 的结果。
var a = 40;
var b = [40];

console.log(a == b); // true

// b 数组 通过 ToPromitive 抽象操作(toString, valueOf)强制转化为 40 进行比较

var str = 'abc';
var str2 = Object(a);

console.log(str === str2); // false
console.log(str == str2); // true

// str2 通过 ToPromitive 进行强制类型的转换,返回字符串 'abc'
// 所以 str == str2

有些值是这样,原因是 == 算法中其他优先级更高的规则。

var a = null;
var b = Object(a); // b = {}
console.log(a == b); // false

var c;
var d = Object(c); // d = {}
console.log(c == d); // false

var e = NaN;
var f = Object(e); // Number(NaN)
console.log(e == f); // false 

特例 - 返回其他数字

Number.prototype.valueOf = function() {
	return 3;
}

console.log(new Number(2) == 3) // true

// new Number(2) 强制类型转换会调用 valueOf 方法,也就是返回 3 
// 3 == 3 结果为 true
// 还有一种 a == 2 && a == 3 结果为true

var i = 1;

Number.prototype.valueOf = function() {
  return ++i;
}

var a = new Number(111);

if (a == 2 && a == 3) {
  console.log('yep, this happened!')
}

特例 - 假值的相等比较

// 常规和非常规的情况
"0" == null // false
"0" == undefined // false
"0" == NaN // false

"0" == false // true - "0"转化为数字 0,false 转化为数字 0,0 == 0
"0" == 0 // true - "0"转化为数字 0,0 == 0
"0" == "" // false

false == null // false
false == undefined // false
false == NaN // false NaN 与任何值都不相等,包括自己
false == 0 // true - false 转化为数字 0, 0 == 0
false == "" // true
false == [] // true
false == {} // false

"" == null // false
"" == undefined // false
"" == NaN // false
"" == 0 // false
"" == [] // true
"" == {} // false

0 == null // false
0 == undefined // false 
0 == NaN // false
0 == [] // true
0 == {} // false