JavaScript的相等(==)与全等(===)

其中的转换规则是什么样的呢
服务器君一共花费了153.499 ms进行了4次数据库查询,努力地为您提供了这个页面。
试试阅读模式?希望听取您的建议

有段代码如下:

if (![] == []) {
    //Code
}

![] == [],true or false?

我们都知道,ECMAScript中有两种类型的相等操作符:

  • 全等与不全等——直接比较而不转换类型
  • 相等与不相等——先转换类型再比较

全等与不全等的逻辑比较简单,而今天我们要关注的是我们平时用得比较多的第二种操作符:相等与不相等。当我们对两个操作数用 == 进行比较的时候,我们分两种情况:== 两边操作数的类型相同与不相同。我们都知道类型不相同时需要先转换类型,但是其中的转换规则是什么样的呢?也许许多人都不曾仔细研究过,今天我们就通过分析![] == []来深入研究一下 == 的比较机制。

两边类型相同

当两边的类型相同时,比较的逻辑就跟 === 一样:

  • 如果类型都是基本类型,则直接比较其值
  • 如果都是引用类型,则比较其引用地址(是否指向同一个对象)

如以下代码:

console.log(5 == 5); //true
console.log('abc' == 'abc'); //true
console.log([] == []); //false,两个不同的引用地址
var a = [], b = a;
console.log(a == b); //true

也许有人会说,既然[] == []为false,那么前面那个![] == []的结果就是true咯?!没错,但是其中的判断逻辑不是这么简单的,因为![]等于false,所以这个比较就相当于false == [],这时两边的类型不一样的,一个是Boolean,一个是Array,所以我们不能简单通过[] == []为false来判断![] == []为true,当我们将[]换成{},这时结果就不一样了。

console.log([] == []); //false
console.log(![] == []); //true
console.log({} == {}); //false
console.log(!{} == {}); //false

也许你会感到糊涂,[]与{}同样是引用类型,为什么![] == []与!{} == {}的结果不一样呢?那是因为Array有其特殊的地方,这时后话,我们先来看下当 == 两边类型不相等时的转换规则。

两边类型不相同

当 == 两边操作数的类型不相同时,会将操作数的类型进行转换相同的类型,通常也叫强制转型,然后再比较其相等性,比如:

console.log(5 == '5'); //true,将字符'5'转换成数字5再比较
console.log(false == 0); //true,先将布尔值false转换成数字0

在转换不同的数据类型时,相等和不相等操作符遵循下列基本规则:

  • 如果有一个操作数是布尔值,则在比较相等性之前现将其转换成数值——false转换成0,而true转换成1
  • 如果一个操作数是字符串,另外一个操作数是数值,在比较相等性之前现将其转换成数值(用Number()方法)
  • 如果一个操作数是对象(引用类型),另外一个操作数不是,则调用对象的valueOf()方法,用得到的原始值按照前面的规则进行比较(如果得到的原始值还是对象,则调用原始值的toString()方法再进行比较)

另外有几个需要注意的地方:

  • null和undefined是相等的(undefined派生于null)
  • 要比较相等性之前,不能将null和undefined转换成其他值(即除null和undefined之外的值都不和null与undefined相等)
  • 一般来说,如果a == b为true的话,那么a != b即为false,反之也可行,但是有一个例外,那就是NaN,NaN不等于任何操作数,包括它自己,即NaN == NaN和NaN != NaN都为false

根据以上规则,我们可以自己写一个比较相等的函数:

function Equal(a, b) {	
	var typeA = typeof a, typeB = typeof b;
	
	//如果有一个操作数是NaN,则总返回false
	//isNaN(undefined)返回true
	if ((isNaN(a) && typeA === 'number') || (isNaN(b) && typeB === 'number')) { return false; }
	
	//如果操作数类型相等,则比较它们的值,否则转换类型
	if (typeA === typeB) {
		return a === b;
	} else {	
		//将undefined转成null(实际上是不转的,此处只是方便后面的比较)
		if (typeA === 'undefined') { a = null; }
		if (typeB === 'undefined') { b = null; }
		
		if (a === null || b === null) {
			return a === b;
		} else if (typeA === 'object' || typeB === 'object') {
			//如果有一个是对象
			//先调用其valueOf方法,如果返回还是object,则调用其toString方法
			var o = (typeA === 'object' ? a : b).valueOf(), other = o === a ? b : a;
			if (typeof o === 'object') {
				o = o.toString();
			}
			return Equal(o, other);
		} else {			
			//如果有Boolean,将其转成Number
			if (typeA === 'boolean') { a = a ? 1 : 0; }
			if (typeB === 'boolean') { b = b ? 1 : 0; }
			//如果其中一个类型是Array,另外一个是Number,Number()返回number或NaN
			if (typeA === 'string' && typeB === 'number') { a = Number(a); }
			if (typeB === 'string' && typeA === 'number') { b = Number(b); }			
			return Equal(a, b);
		}
	}
}
console.log(Equal([], [])); //false
console.log(Equal(![], [])); //true
console.log(Equal({}, {})); //false
console.log(Equal(!{}, {})); //false
console.log(Equal(NaN, NaN)); //false
console.log(Equal(undefined, null)); //true
console.log(Equal(false, null)); //false
console.log(Equal(false, 0)); //true
console.log(Equal(true, 2)); //false

Array.toString()

那么为什么![] == []为true呢?其比较步骤如下:

  • ![]为false,式子相当于false == [],两边类型不同且有一个对象[]
  • 右边的[]调用valueOf()方法,得到的还是对象[],因此再调用toString()的方法,Array的toString()方法相当于Array.join(','),例如[1, 2, 3].toString()等于'1,2,3',而[].toString()等于一个空字符串''({}.toString()等于'[object Object]'),则此时式子相当于false == ''
  • 因为存在布尔值为false,将其转成数值0,此时式子变成0 == ''
  • 最后将右边的空字符串''用Number()方法转成0,0 == 0为true,所以![] == []

因此:

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

总结:由于相等和不相等操作符存在类型转换问题,而为了保持代码中数据类型的完整性,推荐使用全等和不全等操作符(已经强调很久了)。

本文地址:http://www.nowamagic.net/librarys/veda/detail/1010,欢迎访问原出处。

不打个分吗?

转载随意,但请带上本文地址:

http://www.nowamagic.net/librarys/veda/detail/1010

如果你认为这篇文章值得更多人阅读,欢迎使用下面的分享功能。
小提示:您可以按快捷键 Ctrl + D,或点此 加入收藏

大家都在看

阅读一百本计算机著作吧,少年

很多人觉得自己技术进步很慢,学习效率低,我觉得一个重要原因是看的书少了。多少是多呢?起码得看3、4、5、6米吧。给个具体的数量,那就100本书吧。很多人知识结构不好而且不系统,因为在特定领域有一个足够量的知识量+足够良好的知识结构,系统化以后就足以应对大量未曾遇到过的问题。

奉劝自学者:构建特定领域的知识结构体系的路径中再也没有比学习该专业的专业课程更好的了。如果我的知识结构体系足以囊括面试官的大部分甚至吞并他的知识结构体系的话,读到他言语中的一个词我们就已经知道他要表达什么,我们可以让他坐“上位”毕竟他是面试官,但是在知识结构体系以及心理上我们就居高临下。

所以,阅读一百本计算机著作吧,少年!

《代码之美》 聂雪军 (译者)

《代码之美》介绍了人类在一个奋斗领域中的创造性和灵活性:计算机系统的开发领域。在每章中的漂亮代码都是来自独特解决方案的发现,而这种发现是来源于作者超越既定边界的远见卓识,并且识别出被多数人忽视的需求以及找出令人叹为观止的问题解决方案。《代码之美》33章,有38位作者,每位作者贡献一章。每位作者都将自己心目中对于“美丽的代码”的认识浓缩在一章当中,张力十足。38位大牛,每个人对代码之美都有自己独特的认识,现在一览无余的放在一起,对于热爱程序的每个人都不啻一场盛宴。 虽然《代码之美》的涉猎范围很广,但也只能代表一小部分在这个软件开发这个最令人兴奋领域所发生的事情。

更多计算机宝库...