这周在给一些新员工讲JavaScript的时候,谈了==和===的区别,本质来说,===是严格的等同运算符,要求两者类型相同并且值相同;而==运算符在做比较时,会做一定的类型转换。我们在使用过程中应该使用===而不是==,因为这种类型转换后的比较往往都不是你想要的。当时列出了corckfork最喜欢一些例子:

	'' == '0'          // false
	0 == ''            // true
	0 == '0'           // true
	false == 'false'   // false
	false == '0'       // true
	false == undefined // false
	false == null      // false
	null == undefined  // true
	' \t\r\n ' == 0    // true

转换规则

当时有人就问了,那么在做类型转换的时候倒是等式的左边向右边转,还是反过来呢?其实这些都是不对的,我们去看看ECMAScript的规范,会发现它有对于等同运算符做类型转换很明确的比较算法,下面我将其翻译如下: 对于比较x==y,

1.如果x和y类型不同,那么到14步; // //2-13步,为类型相同的比较 // 14.如果x是null,y是undefined,返回true; 15.如果x是undefined,y是null,返回true; 16.如果x是Number,y是String,将y转化成Number,然后再比较; 17.如果x是String,y是Number,将x转化成Number,然后再比较; 18.如果x是Boolean,那么将x转化成Number,然后再比较; 19.如果y是Boolean,那么将y转化成Number,然后再比较; 20。如果x是String或者Number,y是Object,那么将y转化成基本类型,再进行比较; 21.如果x是Object,y是String或者Number,将x转化成基本类型,再进行比较; 22.其他情况均返回false;

ECMA这帮人写的算法过程比较啰嗦,简单一句话来概括就是,对于基本类型Boolean,Number,String,三者之间做比较时,总是向Number进行类型转换,然后再比较;如果有Object,那么将Object转化成这三者,再进行比较;对于null和undefined,只有x,y分别是它们时才相同,其他都为false。

另外,对于转化到Number的算法,细节可以来看ECMAScript的规范,但是基本上下面这个几个表可以覆盖大部分的内容:

type-convert to number (+col) : String Values.

”” (empty string) “-1.6” “0” “1” “1.6” “8” “16” “16.8”

+col

0

-1.6

0

1

1.6

8

16

16.8

type-convert to number (+col) : String Values.

“123e-2” “010” (Octal) “0x10” (Hex) “0xFF” (Hex) “-010” “-0x10” “xx”

+col

1.23

10

16

255

-10

NaN

NaN

type-convert to number (+col) : Other Values.

undefined null true false new Object() function(){ return; }

+col

NaN

0

1

0

NaN

NaN

再回头来看看corkford给出的例子,然后使用上面的规则去判断;

 '' == '0'          // false
//类型相同,毫无疑问,值不同,所以结果为false

0 == ''            // true
//String要像Number转化,''是空String,根据上面的表,转成0,所以结果是true

0 == '0'           // true
//String要像Number转化,根据上面的转化Number表,'0'转成0,所以结果是true

false == 'false'   // false
//有Boolean,转化成Number,所以第一步转化后为0=='false';
//然后'false'向Number转,结果是NaN,最后变成比较0==NaN,那么肯定是false。
//(NaN和任何相比都是false,就算是自己也是false, NaN==NaN //false)

false == '0'       // true
//有Boolean,转化成Number,经过第一次转化就成了0=='0';
//就变成了上面的第3个例子,所以是true

false == undefined // false
//对于undefined和null,只有两边分别是两者才是true,其他都是false;所以是false

false == null      // false
//对于undefined和null,只有两边分别是两者才是true,其他都是false;所以是false

null == undefined  // true
//对于undefined和null,只有两边分别是两者才是true,其他都是false;所以是true
	
' \t\r\n ' == 0    // true
//对于String,先转成Number,对于空String,都将转成0,所以转化后成为0==0,结果为true
//(注意,空字符不仅仅是只是空格,还包括\t\r\n等等,更多可以见ECMAScript spec的9.3.1)

总结

虽然我们了解了==这个坏东西的本质,但是在我们的实际JavaScript编程中是要避免使用==,而是去使用===这个严格的比较运算符。