判断两个变量是否相等在任何编程语言中都是非常重要的功能。
JavaScript 提供了 == 和 === 两种判断两个变量是否相等的运算符,但我们开始学习的时候 JavaScript 的时候,就被一遍又一遍的告知:
=== 要求变量的类型和值均相等,才能返回true。
使用 === 来避免因JavaScript 类型转换带来的问题。
这样增加了 JavaScript 语法的灵活性但是也带来很多头疼的问题:
使用 ==/!=是 ===/!== 来判断两个变量是否相等?
为什么,JS 编码推荐使用 ===/!= 而不是 ==/!=,大部分的编程语言不都是使用==/!=么?
为了要回答这个问题,让我们看一下 JavaScript 所遵守的标准 ECMAScript 对于==和 === 是怎么描述的吧!
=== 详解
Identity Equal或 Strict Equal, 在 ECMAScript -- Java Script 所遵守的标准中,算法的定义为: The Strict Equality Comparison Algorithm , 规则如下:
如果 参数 x 的数据类型和 参数 y 的数据类型不一致,这返回 false
如果 参数 x 的数据类型为 undenfined, 则返回 true
如果 参数 x 的数据类型为 null, 则返回 true
如果 参数 x 的数据类型为 Number, 则:
如果 x 是 NaN 返回 false
如果 y 是 NaN 返回 false
如果 x 是 +0 并且 y 为 -0, 返回 true
如果 x 是 -0 并且 y 为 +0, 返回 true
如果 x 和 y 有着相同的数值,返回 true
返回 false
如果 x 的类型为 String, 且 x 与 y 有着相同的顺序排列的字符串, 返回 true
如果 x 的类型为 boolean, 且 x 与 y 拥有相同的布尔值,返回 true
如果 x 的类型为 Object, 且 x 与 y 指向相同的对象,返回 true
伪代码:
1 functionstrictEqual(x, y) {2 //If Type(x) is different from Type(y), return false.
3 if (!valueEqual(typeof (x), typeof(y))) {4 return false;5 }6
7 //If Type(x) is Undefined, return true.
8 //If Type(x) is Null, return true.
9 if (valueEqual(typeof (x), "undefined") || valueEqual(x, null)) {10 return true;11 }12
13
14 if (valueEqual(typeof (x), "number")) {15 //If x is NaN, return false.
16 if(isNaN(x)) {17 return false;18 }19
20 //If y is NaN, return false.
21 if(isNaN(y)) {22 return false;23 }24
25 //If x is +0 and y is −0, return true.
26 if (valueEqual(x, +0) && valueEqual(y, -0)) {27 return true;28 }29
30 //If x is −0 and y is +0, return true.
31 if (valueEqual(y, +0) && valueEqual(x, -0)) {32 return true;33 }34
35 //If x is the same Number value as y, return true.
36 if(valueEqual(x, y)) {37 return true;38 }39
40 return false;41 }42
43 if (valueEqual(typeof (x), "string")) {44 //If Type(x) is String, then return true if x and y are exactly
45 //the same sequence of characters
46 //(same length and same characters in corresponding positions); otherwise, return false.
47 returnhasSameChar(x, y);48 }49
50 if (valueEqual(typeof (x), "boolean")) {51 returnvalueEqual(x, y);52 }53
54 if (valueEqual(typeof (x), "object")) {55 //Return true if x and y refer to the same object. Otherwise, return false.
56 returnhasSameReference(x, y);57 }58
59 return false;60 }
View Code
逻辑图:
== 详解
Equal, 在两个对比变量数据类型相同时, 和=== 有着一样的行为算法实现,但是当两个对比的变量数据类型不同时,ECMAScript/JavaScript 有着自定义的转换和比较逻辑:参考 The Abstract Equality Comparison Algorithm
如果 x 为 null, 且 y 为 undefined, 返回 true
如果 x 为 undefined, 且 y 为 null, 返回 true
如果 x 的数据类型为 Number, 且 y 的数据类型为 string, 则将 y 转换为 Number,然后进行比较
如果 x 的数据类型为 String, 且 y 的数据类型为 Number, 则将 x 转换为 Number,然后进行比较
如果 x 的数据类型为 Boolean, 将x 转换为数字类型,当 x 为 true 时转换为 1, 否则转换为 0 进行比较
如果 y 的数据类型为 Boolean, 将 y 转换为数字类型,当 y 为 true 时转换为 1, 否则转换为 0 进行比较
如果 x 的数据类型为 String 或者 Number, 且 y 为 Object, 则使用 valueOf 函数,将 y 转换为简单类型进行比较
如果 y 的数据类型为 String 或者 Number, 且 x 为 Object, 则使用 valueOf 函数,将 x 转换为简单类型进行比较
返回 false
从上述定义不难总结出以下几点:
该算法为递归算法,转换后,继续调用其自身直到能比较且返回为止
该算法依赖于 Strict Equal 的实现
进行转换时,具体转换依赖于数据类型的定义的方法,如Number() 函数
伪代码:
1 functionabstractEqual(x, y) {2
3 //if x and y has same type
4 if (valueEqual(typeof (x), typeof(y))) {5 returnstrictEqual(x, y);6 }7
8 //If x is null and y is undefined, return true.
9 if (valueEqual(x, null) &&valueEqual(y, undefined)) {10 return true;11 }12
13 //If x is undefined and y is null, return true.
14 if (valueEqual(x, undefined) && valueEqual(y, null)) {15 return true;16 }17
18 //Type(x) is Number and Type(y) is String,
19 if (valueEqual(typeof (x), "number") && valueEqual(typeof (y), "string")) {20
21 var convertedY =Number(y);22
23 //return the result of the comparison x == ToNumber(y)
24 returnabstractEqual(x, convertedY);25 }26
27 //Type(x) is Number and Type(y) is String,
28 if (valueEqual(typeof (x), "string") && valueEqual(typeof (y), "number")) {29
30 var convertedX =Number(x);31
32 //return the result of the comparison x == ToNumber(y)
33 returnabstractEqual(convertedX, y);34 }35
36 //Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
37 if (valueEqual(typeof (x), "boolean")) {38 var convertedToIntX =Number(x);39
40 returnabstractEqual(convertedToIntX, y);41 }42
43 //Type(x) is Boolean
44 if (valueEqual(typeof (y), "boolean")) {45 var convertedToIntY =Number(y);46
47 //return the result of the comparison ToNumber(x) == y.
48 returnabstractEqual(x, convertedToIntY);49 }50
51 //If Type(x) is either String or Number and Type(y) is Object,
52 if ((valueEqual(typeof (x), "string") || valueEqual(typeof (x), "number")) && valueEqual(typeof (y), "object")) {53 var toPrimitiveY =y.valueOf();54
55 //return the result of the comparison x == ToPrimitive(y).
56 returnabstractEqual(x, toPrimitiveY);57 }58
59
60 //If Type(x) is either String or Number and Type(y) is Object,
61 if ((valueEqual(typeof (y), "string") || valueEqual(typeof (y), "number")) && valueEqual(typeof (x), "object")) {62 var toPrimitiveX =x.valueOf();63
64 //return the result of the comparison x == ToPrimitive(y).
65 returnabstractEqual(toPrimitiveX, y);66 }67
68 return false;69 }
View Code
逻辑图:
附加上本例使用的判断相等的函数的代码,直接使用了 JavaScript 的 == 来实现,为了 demo 么!呵呵,这是一个很号的接口,实际上,我也实现不出来 :).
1 functionvalueEqual(x, y) {2 return x ===y;3 }4
5 functionhasSameChar(x, y) {6 return x ===y;7 }8
9 functionhasSameReference(x, y) {10 return x ===y;11 }
View Code
总结
现在,我们已经知道 == 和 === 在判断两个变量是否相等时所使用的算法的基本实现。帮助我们理解一些 JavaScript 中判断相等时一些"诡异“ 的行为。
把我们写的 Script 放在一个 HTML 文件里,用 Chrome 代开,按 F12, 开始我们的调试吧:
测试 JS 代码
运行结果
JS 代码
运行结果
备注
var x = 1, y = "1";console.log(strictEqual(x,y)); console.log(abstractEqual(x,y))
false, true
var x = 1, y = "1";console.log(x === y); console.log(x == y)
false,true
== 时,y 先转换为数字类型1
var x = 1, y = "not a number";console.log(strictEqual(x,y)); console.log(abstractEqual(x,y))
false, falase
var x = 1, y = "not a number";console.log(x === y); console.log(x == y)
false, false
y 转换为数字类型失败,返回 NaN,NaN 不与任何值相等,包括 NaN 自身
var x = undefined, y = null;console.log(strictEqual(x,y)); console.log(abstractEqual(x,y))
false,true
var x = undefined, y = null;console.log(x===y); console.log(x == y)
false,true
=== 时, null != undefined
== 时,规定了 null 与 undefined 的相等
var x = true, y = 2;console.log(strictEqual(x,y)); console.log(abstractEqual(x,y))
false,false
var x = true, y = 2;console.log(x === y); console.log(x == y)
false,false
true 转换为数字 1
var x = false, y = 0;console.log(strictEqual(x,y)); console.log(abstractEqual(x,y))
false,true
var x = false, y = 0;console.log(x === y); console.log(x == y)
false,true
false 转换为数字 0
var x = {name:'test',valueOf:function(){return 1;}},y = 1; console.log(strictEqual(x,y));console.log(abstractEqual(x,y));
false,true
var x = {name:'test',valueOf:function(){return 1;}},y = 1; console.log(x === y);console.log(x == y);
false,true
x.valueOf() 返回数字 1,与 y 相等