判斷兩個變量是否相等在任何編程語言中都是非常重要的功能。
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 function strictEqual(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 return hasSameChar(x, y); 48 } 49 50 if (valueEqual(typeof (x), "boolean")) { 51 return valueEqual(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 return hasSameReference(x, y); 57 } 58 59 return false; 60 }
?
邏輯圖:
== 詳解
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 function abstractEqual(x, y) { 2 3 // if x and y has same type 4 if (valueEqual(typeof (x), typeof (y))) { 5 return strictEqual(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 return abstractEqual(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 return abstractEqual(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 return abstractEqual(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 return abstractEqual(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 return abstractEqual(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 return abstractEqual(toPrimitiveX, y); 66 } 67 68 return false; 69 }
?
?
邏輯圖:
?
?
附加上本例使用的判斷相等的函數的代碼,直接使用了 JavaScript 的 == 來實現,為了 demo 么!呵呵,這是一個很號的接口,實際上,我也實現不出來 :).


1 function valueEqual(x, y) { 2 return x === y; 3 } 4 5 function hasSameChar(x, y) { 6 return x === y; 7 } 8 9 function hasSameReference(x, y) { 10 return x === y; 11 }
?
總結
現在,我們已經知道 == 和 === 在判斷兩個變量是否相等時所使用的算法的基本實現。幫助我們理解一些 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 相等 |