1. ==和===区别:
首先它们两个引用数据类型都会比较地址值
区别如下:
- === 是严格相等 == 代表相等
- == 数据类型存在隐式转换,如数组转成字符串
简要分析:
//基本数据类型
//1. 存在隐式转换
let arr = [1,2]
let str = "1,2"
arr == str //true 因为arr调用了toString返回"1,2"
//2. toString
arr.toString = ()=>{}
arr == str //false 因为toString函数为空了
//3. valueOf(跳过第二步)
arr.valueOf = ()=>{}
arr == str //false 因为要先经过valueOf返回才能到toString
//引用数据类型
let arr1 = [1,2,3]
let arr2 = [1,2,3]
arr1 == arr2 //false 因为会比较地址值
2. 原始值
隐式转换会牵扯到原始值
原始值,也就是基本数据类型 string number … 除了引用类型Object Array …
如下:
let num = 12; //这是原始值
let numObj = new Number(12); //这是对象 需要使用valueOf转换成原始值
3. 隐式转换
以下代码会成功打印 hello world! 这便是隐式转换
var a = {
i: 1,
toString: function () {
return a.i++;
}
}
if (a == 1 && a == 2 && a == 3) {
console.log('hello world!');
}
隐式转换会经过三个内部函数 ToPrimitive ToNumber ToString (我们无法直接操作)
2.1 返回原始值ToPrimitive
ToPrimitive(input, PreferredType?)会尝试调用valueOf方法和toString方法返回原始值,它有以下两种情况调用:
一般情况 PreferredType自动设置为Number
1、如果输入的值已经是一个原始值,则直接返回它
2、否则,如果输入的值是一个对象,则调用该对象的valueOf()方法,
如果valueOf()方法的返回值是一个原始值,则返回这个原始值。
3、否则,调用这个对象的toString()方法,如果toString()方法返回的是一个原始值,则返回这个原始值。
4、否则,抛出TypeError异常。
特殊(Date对象) PreferredType自动设置为String
1、如果输入的值已经是一个原始值,则直接返回它
2、否则,调用这个对象的toString()方法,如果toString()方法返回的是一个原始值,则返回这个原始值。
3、否则,如果输入的值是一个对象,则调用该对象的valueOf()方法,
如果valueOf()方法的返回值是一个原始值,则返回这个原始值。
4、否则,抛出TypeError异常。
因为valueOf函数会将Number、String、Boolean基础类型的对象类型值转换成 基础类型,Date类型转换为毫秒数,其它的返回对象本身,而toString方法会将所有对象转换为字符串。显然对于大部分对象转换,valueOf转换更合理些,因为并没有规定转换类型,应该尽可能保持原有值,而不应该想toString方法一样,一股脑将其转换为字符串。
上面的例子改成这样
var a = {
i: 1,
toString: function () {
alert("不输出原始值,没有隐式转换")
}
}
if (a == 1 && a == 2 && a == 3) {
console.log('hello world!');
}
不会隐式转换。因为a是一个引用类型,那么它必须先转成原始值。它首先会调用valueOf,发现不行还是引用类型,那么调用toString,发现还是不行,那么便存在内部报错,无法隐式转换。
2.1 ToNumber 和 ToString
对于原始值,js会直接调用这两内部方法隐式转换;对于引用类型,js会经过toPrimitive获取到原始值后再隐式转换。
通过ToNumber将值转换为数字
参数 | 结果 |
---|---|
undefined | NaN |
null | +0 |
布尔值 | true转换1,false转换为+0 |
数字 | 无须转换 |
字符串 | 有字符串解析为数字,例如:‘324’转换为324,‘qwer’转换为NaN |
对象(obj) | 先进行 ToPrimitive(obj, Number)转换得到原始值,在进行ToNumber转换为数字 |
通过ToString将值转换为字符串
参数 | 结果 |
---|---|
undefined | ‘undefined’ |
null | ‘null’ |
布尔值 | 转换为’true’ 或 ‘false’ |
数字 | 数字转换字符串,比如:1.765转为’1.765’ |
字符串 | 无需转换 |
对象(obj) | 先进行 ToPrimitive(obj, String)转换得到原始值,在进行ToString转换为字符串 |
注意,以上转换并不适用任何情况,例如null == 0 为false 因为这样并不会进行隐式转换,而是 null >= 0 为true 因为比较运算符会进行隐式转换,==的情况请往下看
3. == 运算符隐式转换
比较运算 x==y, 其中 x 和 y 是值,返回 true 或者 false。这样的比较按如下方式进行:
1、若 Type(x) 与 Type(y) 相同, 则
1* 若 Type(x) 为 Undefined, 返回 true。
2* 若 Type(x) 为 Null, 返回 true。
3* 若 Type(x) 为 Number, 则
(1)、若 x 为 NaN, 返回 false。
(2)、若 y 为 NaN, 返回 false。
(3)、若 x 与 y 为相等数值, 返回 true。
(4)、若 x 为 +0 且 y 为 −0, 返回 true。
(5)、若 x 为 −0 且 y 为 +0, 返回 true。
(6)、返回 false。
4* 若 Type(x) 为 String, 则当 x 和 y 为完全相同的字符序列(长度相等且相同字符在相同位置)时返回 true。 否则, 返回 false。
5* 若 Type(x) 为 Boolean, 当 x 和 y 为同为 true 或者同为 false 时返回 true。 否则, 返回 false。
6* 当 x 和 y 为引用同一对象时返回 true。否则,返回 false。
2、若 x 为 null 且 y 为 undefined, 返回 true。
3、若 x 为 undefined 且 y 为 null, 返回 true。
4、若 Type(x) 为 Number 且 Type(y) 为 String,返回比较 x == ToNumber(y) 的结果。
5、若 Type(x) 为 String 且 Type(y) 为 Number,返回比较 ToNumber(x) == y 的结果。
6、若 Type(x) 为 Boolean, 返回比较 ToNumber(x) == y 的结果。
7、若 Type(y) 为 Boolean, 返回比较 x == ToNumber(y) 的结果。
8、若 Type(x) 为 String 或 Number,且 Type(y) 为 Object,返回比较 x == ToPrimitive(y) 的结果。
9、若 Type(x) 为 Object 且 Type(y) 为 String 或 Number, 返回比较 ToPrimitive(x) == y 的结果。
10、返回 false。
上面主要分为两类,x、y类型相同时,和类型不相同时。
类型相同时,没有类型转换,主要注意NaN不与任何值相等,包括它自己,即NaN !== NaN。
类型不相同时,
1、x,y 为null、undefined两者中一个 // 返回true
2、x、y为Number和String类型时,则转换为Number类型比较。
3、有Boolean类型时,Boolean转化为Number类型比较。
4、一个Object类型,一个String或Number类型,将Object类型进行原始转换后,按上面流程进行原始值比较。