JS中== 和=== 的区别

问题的出现

之前只是大致了解 == === 的区别,之前认为 == 是比较值的大小,=== 不仅需要比较值,还需要比较值的类型。
之前在一次逻辑处理中,做验证数据不为空时写了这样一个逻辑。varietyData数组中元素每个字段都不能为空字符串或空数组。

let varietyData =[{value1:'123',value2:'456',value3:0,value4:[1,2,3]},
                  {value1:'123',value2:'456',value3:0,value4:[3]},
                  {value1:'123',value2:'456',value3:0,value4:[]}
                 ];
let obj = {value1:'姓名',value2:'爱好',value3:'成绩',value4:'资源'};
varietyData.every((val,index)=>{
let index = Object.keys(val).every(e=>{
  if(val[e] == ''||val[e] == []){
    this.$message({type:"warning",message:`${index+1}行,${obj[e]}不能为空!`});
    return false
  }else{
    return true;
  }
})

当value3的值为0时,数据应该是通过的,结果验证逻辑一直不通过,打断点调试后才发现问题出在这里。

console.log(0 == '');  //true
console.log(0 == []);  //true

解决办法

之后将 == 改成 === 就没问题了。

let varietyData =[{value1:'123',value2:'456',value3:0,value4:[1,2,3]},
                  {value1:'123',value2:'456',value3:0,value4:[3]},
                  {value1:'123',value2:'456',value3:0,value4:[]}
                 ];
let obj = {value1:'姓名',value2:'爱好',value3:'成绩',value4:'资源'};
varietyData.every((val,index)=>{
let index = Object.keys(val).every(e=>{
  if(val[e] === ''||val[e] === []){
    this.$message({type:"warning",message:`${index+1}行,${obj[e]}不能为空!`});
    return false
  }else{
    return true;
  }
})

知识梳理

对于 == 和 === 的比较规则,想趁着这次机会重新梳理下。

全等运算符(===)

官方描述

严格相等运算符(===)也叫全等运算符,其会检查两个操作数是否相等,并且返回一个布尔值结果。

7.2.15Strict Equality Comparison

The comparison x === y, where x and y are values, produces true or false. Such a comparison is performed as follows:

  1. If Type(x) is different from Type(y), return false.
  2. If Type(x) is Number, then
    1. If x is NaN, return false.
    2. If y is NaN, return false.
    3. If x is the same Number value as y, return true.
    4. If x is +0 and y is -0, return true.
    5. If x is -0 and y is +0, return true.
    6. Return false.
  3. Return SameValueNonNumber(x, y).

SameValueNonNumber方法描述

7.2.12SameValueNonNumber ( x, y )

The internal comparison abstract operation SameValueNonNumber(x, y), where neither x nor y are Number values, produces true or false. Such a comparison is performed as follows:

  1. Assert: Type(x) is not Number.
  2. Assert: Type(x) is the same as Type(y).
  3. If Type(x) is Undefined, return true.
  4. If Type(x) is Null, return true.
  5. If Type(x) is String, then
    1. If x and y are exactly the same sequence of code units (same length and same code units at corresponding indices), return true; otherwise, return false.
  6. If Type(x) is Boolean, then
    1. If x and y are both true or both false, return true; otherwise, return false.
  7. If Type(x) is Symbol, then
    1. If x and y are both the same Symbol value, return true; otherwise, return false.
  8. If x and y are the same Object value, return true. Otherwise, return false.
比较规则
  1. 若两个操作数类型不同,返回false。
  2. 若两个操作数类型为Number,则会有一些特殊情况,NaN === NaN结果为flase,+0 === -0结果为true。
  3. 若两个操作数都为 null,或者两个操作数都为 undefined,返回 true。
  4. 若两个操作数为字符串类型,必须拥有相同顺序的相同字符。
  5. 若两个操作数为Boolean类型,必须同时为 true 或同时为 false。
  6. 若两个操作数都是对象,只有当它们指向同一个对象时才返回 true。
let obj1 = {a:1};
let obj2 = obj1;
let obj3 = {a:1};

console.log(obj1 === obj2);  //true
console.log(obj2 === obj3);  //false

相等运算符(==)

官方描述

相等运算符(==||!=),提供非严格相等语义,在ECMAScript中的描述是这样的:

7.2.14 Abstract Equality Comparison

The comparison x == y, where x and y are values, produces true or false. Such a comparison is performed as follows:

  1. If Type(x) is the same as Type(y), then
    1. Return the result of performing Strict Equality Comparison x === y.
  2. If x is null and y is undefined, return true.
  3. If x is undefined and y is null, return true.
  4. If Type(x) is Number and Type(y) is String, return the result of the comparison x == ! ToNumber(y).
  5. If Type(x) is String and Type(y) is Number, return the result of the comparison ! ToNumber(x) == y.
  6. If Type(x) is Boolean, return the result of the comparison ! ToNumber(x) == y.
  7. If Type(y) is Boolean, return the result of the comparison x == ! ToNumber(y).
  8. If Type(x) is either String, Number, or Symbol and Type(y) is Object, return the result of the comparison x == ToPrimitive(y).
  9. If Type(x) is Object and Type(y) is either String, Number, or Symbol, return the result of the comparison ToPrimitive(x) == y.
  10. Return false.
比较规则

其比较规则如下:

相同类型比较

如果操作数具有相同的类型,则比较结果和**全等运算符(===)**比较结果一样,同上面的全等运算符比较。

不同类型比较
null 和 undefined

如果x,y两个操作数,x为null,y为undefined 或x为undefined,y为null,则返回true。
image.png

Number 和 String

如果x,y两个操作数,x为Number类型,y为String类型或y为Number类型,x为String类型,会先将String类型数据转化为Number类型,再做比较。下面两者是等价的。
image.png
需要注意的是:Number()将字符串转化为数字时,空字符串会转化为0,即Number('')的值为0,也就是说 0 == ''结果为 true。
image.png
带非数字字符的字符串会转化为NaN
image.png

Boolean 和其他基础类型

如果x,y两个操作数,x为Boolean类型,y为其他类型或y为Boolean类型,x为其他类型,则通过Number将Boolean类型转化为数字,再进行比较。其中true转化为1,false转化为0
image.png
image.png
如果另一个操作数是字符串类型,比较时会将字符串转化为数字,再进行比较。于是我们就会发现一种比较有趣的情况, false == '0'false == '' 都为 true,''=='0'为false。这是因为同类型和不同类型的比较规则是不同的,想通过他们之间的连等来判断是不可取的。
image.png

Symbol 和 其他基础类型

Symbol的值都是唯一的,所以它只在与自身比较时才为true,与其他值比较时都为false。
image.png

BigInt 和 其他基础类型

BigInt和Number类型相似,进行比较时会先将其他类型转化为Number类型,再进行比较。
image.png

Object 和 其他基础类型

如果x,y两个操作数,x为Object,y为Symbol,Number,String类型,则会先将Object对象类型数据转化为基本类型,按此顺序使用对象的Symbol.toPrimitive,valueOf(),toString()方法将对象转化为基本类型(这个基本类型转换与相加中使用的转化相同),再进行比较。

  • Symbol.toPrimitive: 是内置的symbol属性,其指定了一种接收首选类型并返回对象原始值的方法,它被所有的强制类型转化算法优先调用
  • **valueOf:**Object实例的valueOf()方法,将this值转化为对象。该方法被派生类重写,以实现自定义类型转换的逻辑。
  • **toString:**方法返回一个表示该对象的字符串。旨在重写(自定义)派生类对象的类型转换逻辑。

总结一下,Object类型数据与基本类型数据进行比较时,如果Object类型数据有Symbol.toPrimitive方法,则会优先调用此方法,将数据转化为基本类型数据。没有则会调用valueOf方法返回一个数据,若返回的数据是对象则再调用toString方法将其转化为基本类型。
我们通过下面的例子来验证下它的转换过程
image.png
在上面的例子中,valueOftoString都是原型对象(Object.prototype)上的方法,因此可以直接调用,但Symbol.toPrimitive需要我们自己定义。

let obj = {
  [Symbol.toPrimitive](hint){
    if(hint == 'default'){
      return 42
    }else{
      return 43;
    }
  }
}
console.log(obj == 42);  //true

上面例子比较结果为true,其中Symbol.toPrimitive方法接收一个参数作为转换原始值的类型,这个参数的默认值为default。我们在这个对象上定义了Symbol.toPrimitive方法,再将对象转化为原始值时,会首先调用这个方法,没有查找到这个方法才会使用valueOftoString方法进行转换。
想了解更多Symbol.toPrimitive相关知识,请移步:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toPrimitive

验证了Object是如何转换为基础数据类型的,接下来验证下特殊对象(数组,函数)是如何转换的?
1,空数组的转换
image.png
空数组经过转化后的基本类型数据为空字符串,因此相等运算[] == ''[] == 0的结果为true。
2,非空数组的转换
image.png
image.png
通过上面例子可以看出非空数组转化为基本数据类型时,会先将数组元素转化为字符串,然后再用逗号拼接起来。
3,函数的转换
image.png
通过上面的例子可以看出函数转化为基本数据类型时,会将函数代码转化为字符串格式。

总结

1,如果两个操作数类型相同,则返回 x === y的结果
2,如果两个操作数类型不相同,且均为基础数据类型,则有以下几种情况
(1)类型为null或undefined时,除与自身比较为true外,还有null == undefined 为true,其余情况为false。
(2)类型为Symbol时,只与自身比较为true,其余情况为false。
(3)类型为Boolean时,会将Boolean类型数据转化为Number类型数据,true为1,false为0,再进行比较
(4)其余的情况比较时,先通过Number()方法转化为数字后,再进行比较。
3,如果某个操作数为对象,则通过Symbol.toPrimitive,valueOf,toString将其转化为基础数据类型后,再进行比较。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值