在JavaScript中什么時候使用==是正確的?
在JavaScript中什么情況下使用==是正確的?簡而言之:沒有。這篇文章來看五種情況下總是使用===,并且解釋為什么不用==。
JavaScript有兩種操作符用來比較兩個值是否相等 [1]:
-
嚴格相等 === 僅考慮相同類型的值是否相等。
-
“正常”(或非嚴格)相等操作符 == 在比較之前,嘗試為不同類型的值進行轉換,然后類似嚴格相等。
給JavaScript初學者的建議是完全忘掉 == ,并且總是使用 ===。事實證明,后者是更符合常規的。有五種案例,表面看起來可以不遵從規則,但真的不是這樣。從現在開始,我使用下面的規則:
意圖清晰的代碼勝過更簡潔的代碼。 記住:你的代碼僅寫一次,但被閱讀很多次——盡可能保證對閱讀者友好。
例1:你清楚自己在比較什么
例如,使用typeof操作符[2],你能確保結果是字符串。然后可以放心使用 ==,因為我們確定不會在發生類型轉換。
if (typeof x == "function") { ... }
然而,有兩個反對這樣做的原因:
-
一致性:使用==對一致性沒有任何好處,那么為什么不避免使用呢?
-
簡單和性能:一般來說,=== 是最簡單的操作符,因為它不進行類型轉換。JavaScript引擎的性能參差不齊[3],但在大部分瀏覽器中 === 比 == 速度更快。
-
例2:與undefined和null做比較
當使用 == 時,undefined和null在結果上等價——他們彼此相等,互相相等,但沒有意義(包括JavaScript中的能被轉換為false的值):
> null == null true > undefined == null true > false == null false > 0 == null false
因此,下面的if語句檢測的是null或undefined。
if (x == null) { ... }
然而,這是否出于簡潔性考慮,意圖并不清晰:如果你同時也檢測undefined,那么你可以這樣寫。然而,如果JavaScript初學者讀到你的代碼,他們可能認為你僅僅檢測null。如果高手讀到你的代碼,他們可能認為你寫錯了,并且應該寫成 ===。
if (x === undefined || x === null) { ... }
如果你有點懶的話,上面的代碼能被精簡為:
if (!x) { ... }
和上面一樣的警告:這條件成立,如果x有否定類型的值。
undefined null false 0 ""
例3:比較字符串和數字
場景:你正工作在用戶界面代碼或編碼處理服務器端參數。你可能會把數字編碼為字符串。如果x是一個字符串,你可以像下面這樣比較:
if (x == 123) { ... }
但問什么不告訴其他閱讀你代碼的人,如果x不是數字,它將被轉換為數字?
if (Number(x) === 123) { ... }
例4:比較對象和原始值
使用 == 時你可以將一個原始值和其他原始值或包裝類型 [4]實例做比較:
> function isAbc(x) { return x == "abc" } > isAbc("abc") true > isAbc(new String("abc")) true
而使用 === 時,你不能這樣做:
> new String("abc") === "abc" false
左邊是一個對象而右邊是原始值。因為他們類型不同所以不嚴格相等。然而,你同樣需要向閱讀你代碼的人解釋清楚你的意圖。下面是表達式:
x == "abc"
你的目的是什么?
-
你真的想讓一個包裝字符串和右邊的字符串作比較嗎?這似乎不太可能,但如果確實是這樣,你應該小心翼翼并給出文檔記錄。
-
你想將x轉換為字符串?那應該寫的更明確String(x) === "abc"
-
你想提取包裝變量的原始值?那你應該考慮下面的寫法x.valueOf() === "abc"
例5:JavaScript是靈活的語言——我的代碼也應該這樣
理由是這樣的:我想我的代碼像JavaScript一樣靈活。== 操作符幫我實現這一目的。例如JavaScript的靈活體現在它自動轉換值類型:
> "abc" + false 'abcfalse' > 3 + true 4 > +"73" 73
有幾個理由反駁上述假說:
1.即使會自動轉換但并不總是按你需要的方式轉換。例如:
> !"false" false > 7 + "3" '73' > Number("") 0
2.非嚴格相等的轉換規則非常復雜:
> 2 == false false > 2 == true false > Boolean(2) true
3.顯示轉化加上嚴格相等的代碼更具描述性。比較:靈活的非嚴格相等。
function is123Implicit(x) { return x == 123; } > is123Implicit(123) true > is123Implicit(new Number(123)) true > is123Implicit("123") true
替代方案:靈活的顯式轉換和嚴格相等。
function is123Explicit(x) { x = Number(x); return x === 123; } > is123Explicit(123) true > is123Explicit(new Number(123)) true > is123Explicit("123") true
4.有人說您的代碼缺少靈活性?可以說JavaScript的默認靈活性利大于弊(對于學習難度而言)。寫防御型的代碼更容易暴漏Bug。is123Explicit()的防御型版本看起來像下面這樣:
function is123Defensive(x) { if (typeof x !== "number") { throw new TypeError("Not a number: "+x); } return x === 123; }
如果你想給函數傳遞任何非原始數字值,你必須先進行類型轉換。
結論
我希望我讓你確信堅持簡單的規則——”不用 ==“的意義,不只是對新手。在你的代碼中魔法越少,通常意味著越容易理解。
相關閱讀
注
英文:http://www.2ality.com/2011/12/strict-equality-exemptions.html