弄懂JavaScript中的 == 和 ===

625 阅读4分钟

一句话总结=====的主要区别

==允许在相等中进行隐式强制类型转化,而===不允许。

(隐式强制类型转化的意思是JS引擎会悄咪咪的对不同类型的数据转换类型)

1.Object vs Object

两个对象指向同一个值时视为相等,不发生强制类型转换。

let a = { text: 1};
let b = { text: 1};
let c = a;

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

需要注意的是构造函数调用(new)返回的是个对象,而不是基本数据类型。

let c = new Boolean(true);
let d = new Boolean(true);
console.log( c == d);// false
console.log( c === d);// false

2. Object vs 非Object

2.1 两个值的类型相同

就仅比较它们的内容是否相等,不需要进行类型转换。

1.字符串类型

let a = '123';
let b = '123';
console.log(a == b);// true
console.log(a === b);// true

2.布尔类型

let e = true;
let f = true;
let g = false;

console.log( e == f);// true
console.log( e == g);// false

2.2 两个值的类型不同

==在比较时会发生强制类型转换,会将其中之一或者两者都转换为相同的类型后比较

===不会发生类型转换,类型不同,直接就是不等。

let a = 123;
let b = '123';

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

1. 字符串与数字进行比较

两者都转换成字符串后比较。

2. 布尔类型与其他类型进行比较

布尔类型先转换成Number类型,Number类型再与其他类型进行比较,可能还要二次类型转换。

3. undefined、null的对比

==中,null与undefined相等,除此之外其他值都不和他们两个相等。

consoel.log( null == undefined);// true
consoel.log( null === undefined);// false
console.log( null === null);// true
console.log( undefined === undefined);// true

比较难记,个人采用的方式是记转换时的优先级:字符串 > Number > Boolean , undefined 和 null 在 == 中相等,除此之外与其他的都不等。

4. 非对象与对象之间的比较

用对象的toPrimitive()后的结果与非对象比较。valueOf()优先级大于toString()

let c = { text: 123 };
Object.prototype.toString = function() {
  return 123;
}
Object.prototype.valueOf = function() {
  return 456;
}
c.valueOf();
c.toString();
console.log(c == 456);// true
console.log(c === 456);// false

image.png

3. 扩充知识点:对象的toPrimitive

根据牛津词典的解释,primitive的意思是原始的

image.png

所以,对象的toPrimitive,可以简单理解为获取对象的原始值。

对象的原始值,是什么意思的? 举个🌰

let a = { text: 123 };
console.log(a.toString());// [object Object]

我们定义了一个对象a,同时调用了toString()方法, 但是我们实际上并没有写toString()方法,a是怎么访问到并被执行的呢?

这里JS引擎内部的实现是a通过原型链访问到了定义到Object.prototype上的toString()方法。所以a必然有个指针,指向Object.prototype, a本身存储了text:123这样的数据信息,也有js引擎内部赋予的其他附加信息,toPrimitive()就是拿存储在a上的数据信息。

image.png

如图,除了对象的值外,对象本身还存在[[Prototype]]的指针。 上面还有toValue()toString()方法。

但是,问题又来了,为什么需要toValue()toString()两个方法来获取对象存储的数据信息呢? 只用一个不行吗?

  • toString()方法的主要目的是返回一个可以表示该对象的字符串。这个方法在不同类型的对象中可能有不同的实现,以便于返回能够代表该对象意义的字符串。例如,数组的toString()方法会将数组转换成一个以逗号分隔的元素列表字符串,而Date对象的toString()方法会返回一个可读的日期时间字符串。

  • valueOf()方法的主要目的是返回对象的“原始值”。这个方法通常用于获取对象的默认表示,特别是在数学运算或者逻辑运算中。例如,在数值运算中,valueOf()会被调用以获取数值形式的值。

这两个方法之所以都存在,是因为它们在JavaScript的内部操作中扮演着重要的角色,特别是在类型转换和比较操作中。JavaScript是动态类型的语言,所以它需要一种方式来确定在特定上下文中应该使用对象的哪种表示。例如,当你尝试将一个对象当作字符串使用时,JavaScript会尝试调用toString()方法;而当你需要对象的原始值时,它会调用valueOf()方法。

一般情况下,valueOf()优先级会大于toString();

Object.prototype.toString = function() {
  return 'toString';
}
Object.prototype.valueOf = function() {
  return 'valueof';
}
var myObject = {
  name: "myObject",
};

console.log('me ' + myObject + ' say'); // me valueof say
console.log(1 + myObject); //1valueof

4. 注意点

1.任何情况都不要用something == truesomething == false

2.NaN == NaN的结果为false,因为NaN不等于NaN,NaN是JavaScript中唯一不等于自身的数

3.Symbol不能强制转换为数字(显式和隐式都会语法报错),但是可以强制转换为布尔值(显式和隐式结果都是true)

4.&& 和 || 运算符的返回值不一定是布尔类型,而是两个操作数中其中一个的值