以前总是把学习记录写在云笔记里,后来觉得这样很少会再去打开阅读,所以现在开始把一些学习中的细节分享跟大家一起交流学习,不对之处,欢迎指正。
一、==(宽松相等)和===(严格相等)的定义
之前在我脑海里的定义:“==是比较两个数是否相等,不去对比类型,===是比较两个数严格相等,会去比较地址”
后来才发现这个说法是不准确的。
准确的说法应该是:“==允许在相等比较中进行隐式强制类型转换,而===不允许”。也就是说,两种方式都会去检查操作数的类型。
二、==的比较方式
不管是什么类型的两个数比较,==都会将其一或者两者都转为相同类型后再进行比较
1、字符串和数字之间的相等比较(左转右还是右转左?)
var a = 25;
var b = "25";
a == b; // true
a === b; // false,(因为不强制转换类型,所以a字符串和b的number类型不相等)
那么到底是a从25转为字符串,还是b的“25”转为数字呢?
根据ES5规范11.9.3.4-5的定义:
(1)如果type(x)为字符串,type(y)为数字,则返回ToNumber(x) == y的结果
(2)如果type(x)为数字,type(y)为字符串,则返回x = ToNumber(y)的结果
总结:所以不能以转换左边还是右边为主。(数字跟字符串对比,会将字符串先转为数字进行对比)
2、其他类型和布尔类型之间的相等比较
==最容易出错的就是true和false与其他类型之间的比较
var a = "42";
var b = true;
a == b // 我们知道“41”是一个真值,那为什么跟true==相比却输出false呢?
如果我们不知道哪个先转,就会出现上述a==b为true的错觉
根据ES5规范11.9.3.4-5的定义:
(1)如果type(x)为布尔值,type(y)为其他类型,则返回ToNumber(x) == y的结果
(2)如果type(y)为布尔值,type(x)为其他类型,则返回x = ToNumber(y)的结果
所以b = true,会被Number(true)转化为1,而1 == "42"会根据第一条再进行隐式强制类型转换,所以最终1 == 42 为false。
总结:布尔值跟其他类型对比,会将布尔值先转为数字后再进行对比,避免== true和==false写法。
3、undefined和null之间的相等比较
在==中,undefined和null之间也会发生隐式强制转换。
根据ES5规范11.9.3.4-5的定义:
(1)如果type(x)为null,type(y)为undefined,则返回true
(2)如果type(x)为undefined,type(y)为null,则返回true所以在==中,undefined和null是可以相互转化相等的
常见的判断写法:
if (a === undefined || a === null) {
// dosomething...
}
可以改为
if (a == null) {
// dosomething...
}
var a = null;
var b; // undefined
a == b // true
a == null // true
b == null // true
a == false // false
b == false // false
a == '' // false
b == '' //false
a == 0 // false
b == 0 //false
总结:null和undefined是相等的,并且和自身相等,除此之外,和其他数都不相等
4、对象和非对象之间的相等比较
根据ES5规范11.9.3.4-5的定义:
(1)如果type(x)为对象,type(y)为字符串或数字,则返回ToPrimitive(x) == y的结果
(2)如果type(x)为字符串或数字,type(y)为对象,则返回x = ToPrimitive(y)的结果
注:这里type没有布尔值,是因为布尔值会被强制转化为数字
var a = 42;
var b = [42]
a == b // true[42]会调用ToPrimitive操作返回"42","42" == 42,会再转成42 == 42。
关于ToPrimitive的用法网上有很多文章讲的很详细,这里不再说明。
一道很奇怪的题目
if(a == 2 && a == 3) {
// dosomething...
}
// 有什么数会同时等于2跟3呢?
// 分析:2比3先执行,那么可不可以先让2执行之后再加1,是不是就可以等于3呢
var i = 2;
Number.prototype.valueOf = function() {
return i++
}
var a = new Number(20);
// 每次a.valueOf()调用都会产生副作用
if (a == 2 && a == 3) {
alert('成功执行')
}