JavaScript中的相等比较

参考:MDN相等性判断

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

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

Moral of the story:
Always use 3 equals unless you have a good reason to use 2.
能用===就用===!!!

===

全等操作符比较两个值是否相等,两个被比较的值在比较前都不进行隐式转换

如果两个被比较的值具有不同的类型,这两个值是不全等的。具体规则:

  • 如果类型不同,就[不相等]
  • 如果两个值都是null,或者都是undefined,那么[相等]。
  • 如果两个都是数值,并且是同一个值,那么[相等]。但是+-0和NaN要特殊对待
    • +0,-0,0视作相等
    • NaN与任何值都不等,包括NaN
  • 如果两个都是字符串,每个位置的字符都一样,那么[相等];否则[不相等]。
  • 如果两个值都引用同一个对象或函数,那么[相等];否则[不相等]。
1
2
3
4
5
6
7
8
9
10
11
// 这些是===符合预期的情况
console.log(true === 1); // false
console.log({} === {}); // false
console.log("2" === 2); // false
// 这些情况在不同JavaScript引擎中表现不同,但仍被认为相等
console.log(+0 === -0); // true
console.log(+0 === 0); // true
console.log(-0 === 0); // true
// 要确定NaN的相等性,必须使用极为讨厌的isNaN()
console.log(NaN === NaN); // false
console.log(isNaN(NaN)); // true

Object.is

Object.is的行为方式与===相同,但是对于NaN和-0和+0进行特殊处理

  • ===
    • +0,-0,0视作相等
    • NaN与任何值都不等,包括NaN
  • Object.is
    • +0和0相等,和-0不相等
    • NaN和NaN相等
1
2
3
4
5
6
7
8
9
10
// 行为方式与===相同
console.log(Object.is(true, 1)); // false
console.log(Object.is({}, {})); // false
console.log(Object.is("2", 2)); // false
// 正确的0、-0、+0相等/不等判定
console.log(Object.is(+0, -0)); // false *******
console.log(Object.is(+0, 0)); // true
console.log(Object.is(-0, 0)); // false ******
// 正确的NaN相等判定
console.log(Object.is(NaN, NaN)); // true ********

+0 -0

+0和-0的区别

参考

  • +0是0,-0是别的
  • 主要是浮点数表示中符号位不同
  • 表现不同:加减乘除运算
1
2
3
4
5
6
+0 + (+0) = +0
+0 + (-0) = +0
-0 + (+0) = +0
-0 + (-0) = -0
1/-0 = -Infinity
1/+0 = Infinity

判断+-0

1
2
3
4
5
6
7
8
//判断是否为+0
function isPositiveZero(num){
return num === 0 && 1 / num > 0
}
//判断是否为-0
function isNegativeZero(num){
return num === 0 && 1 / num < 0
}

+0和-0的应用场景

隐式类型转换:String转Number用-0,此外*1或/1也行

1
2
3
4
"123"+0  // '1230'
"123"-0 // 123
"123"*1 // 123
"123"/1 // 123

NaN

MDN: NaN

NaN 是一个全局对象的属性。

NaN 属性的初始值就是 NaN,和 Number.NaN 的值一样。在现代浏览器中(ES5 中), NaN 属性是一个不可配置(non-configurable),不可写(non-writable)的属性

NaN出现的情况

编码中很少直接使用到 NaN。通常都是在计算失败时

  • 作为 Math 的某个方法的返回值出现的(例如:Math.sqrt(-1)
  • 或者尝试将一个字符串解析成数字但失败了的时候(例如:parseInt("blabla"))。

判断一个值是否是 NaN

返回false的情况

  • 通过 =====与其他任何值比较都将不相等, 包括与其他 NaN 值进行比较。

返回true的情况

在执行自比较之中:也只有 NaN 不等于它自己。

==

在比较前将两个被比较的值转换为相同类型

在转换后(等式的一边或两边都可能被转换),最终的比较方式等同于全等操作符 === 的比较方式

image-20220413113049671

如果两个值类型相同,进行 === 比较。

  • 注意NaN和NaN,规定[不相等]!

如果两个值类型不同。根据下面规则进行类型转换再比较:

  • 如果一个是null、一个是undefined,那么[相等]

    • null、undefined和其他数据类型比较都[不相等]
  • 如果其中之一为Number

    • 另一个是String,就转成Number判断
      • 返回值可能是NaN或数值
    • 另一个是Boolean,就转成Number判断
      • true->1,false->0
    • 另一个是Object,调用ToPrimitive比较
  • 如果是String和Boolean

    • 都转化成Number
  • 如果是Object

    • 调用ToPrimitive比较

Number

MDN: Number

Number 对象主要用于:

  • 如果参数无法被转换为数字,则返回 NaN
  • 在非构造器上下文中 (如:没有 new 操作符),Number 能被用来执行类型转换。

使用new操作符

new,返回对象,由Number构造函数产生

不new,返回Number类型的一个数值

1
2
3
4
5
new Number(value);
var a = new Number('123'); // a === 123 is false
var b = Number('123'); // b === 123 is true
a instanceof Number; // is true
b instanceof Number; // is false

ToPrimitive

Symbol.toPrimitive

MDN: Symbol.toPrimitive

这是一个对象的内置函数属性,无法从外部调用,但是我们可以通过触发隐式类型转换观察它的行为

1
2
3
4
var obj1 = {};
console.log(+obj1); // NaN
console.log(`${obj1}`); // "[object Object]"
console.log(obj1 + ""); // "[object Object]"

可以重写Symbol.toPrimitive属性,hint 参数的取值是 "number""string""default" 中的任意一个。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 接下面声明一个对象,手动赋予了 Symbol.toPrimitive 属性,再来查看输出结果
var obj2 = {
[Symbol.toPrimitive](hint) {
if (hint == "number") {
return 10;
}
if (hint == "string") {
return "hello";
}
return true;
}
};
console.log(+obj2); // 10 -- hint 参数值是 "number"
console.log(`${obj2}`); // "hello" -- hint 参数值是 "string"
console.log(obj2 + ""); // "true" -- hint 参数值是 "default"

转换规则

学习js原始值转换的抽象操作 toPrimitive

hint 参数是"string",Object->String

判断对象中有没有toString()方法

  • 有,调用toString()方法。

    • 如果返回一个原始值,非字符串的转化为字符串,返回字符串
  • 没有,或者toString()返回一个非原始值,那么js会调用valueOf()方法。

    • 如果返回一个原始值,非字符串的转化为字符串,返回字符串
  • 否则,js抛出一个类型错误异常。

hint 参数是"number/default",Object->Number

判断对象中有没有valueOf()方法

  • 有,调用valueOf()方法
    • 返回一个原始值,则js会将其转换为数字(如果需要的话)并返回这个数字。
  • 没有,如果对象具有toString()方法,则调用
    • 返回一个原始值(字符串直接量),则js将其转换为数字类型,并返回这个数字。
  • 否则,js抛出一个类型错误异常。

判断

参考:JS比较表

下面的情况==会输出什么?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
NaN==NaN // false, NaN与任何值都不等

// true
true==1
true=="1"
true==[1]
false==0
false=="0"
false==[]
false==[[]]
false==[0]
false=={} // false

"1,2,3"==[1,2,3] // true, Array.prototype.toString => '1,2,3'
'[object Object]'=={} // true, Object.prototype.toString({})=>'[object Object]'

"123"==[123] // true
new String("123")=="123" // true
new String("123")==[123] // false, 因为是两个Object比较
------ 本文结束 ❤ 感谢你的阅读 ------
------ 版权信息 ------

本文标题:JavaScript中的相等比较

文章作者:Lury

发布时间:2022年04月13日 - 13:10

最后更新:2022年04月13日 - 13:18

原始链接:https://luryzhu.github.io/2022/04/13/JavaScript/sum1_equal/

许可协议:署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。