JavaScript:什么時(shí)候能用==
答案是:永遠(yuǎn)不要用.本文依次否定了五種看起來可以使用==的地方,同時(shí)解釋了為什么.
JavaScript中有兩個(gè)運(yùn)算符用來判斷兩個(gè)值是否相等:
嚴(yán)格相等運(yùn)算符===,必須類型相同且值相同.
普通的(寬容的)相等運(yùn)算符==,在比較值是否嚴(yán)格相等之前,首先進(jìn)行類型轉(zhuǎn)換.
給JavaScript初學(xué)者的建議是:完全忘掉==,總是使用===.實(shí)踐證明,這樣做是完全正確的.有五種案例看起來可以反駁這一論點(diǎn),但其實(shí)沒有.從現(xiàn)在開始,我們的指導(dǎo)原則是:
比起簡(jiǎn)潔,我們更喜歡意圖清晰的代碼.
記住:你的代碼只寫一次,但可能要讀很多次 – 請(qǐng)盡可能的讓你的代碼易讀.
案例1:你知道你在比較什么
例如,如果使用的是typeof操作符,你可以確定它返回來的是個(gè)字符串.那么使用==就是安全的,因?yàn)槲覀兛梢源_定這樣的比較不會(huì)有任何的類型轉(zhuǎn)換:
- if (typeof x == "function") {
- ...
- }
可是,有兩個(gè)理由讓我們不去這樣做:
一致性: 如果你在這里使用了==,你不會(huì)得到任何的好處,那還何必破壞統(tǒng)一的規(guī)則去使用它?
簡(jiǎn)單和性能: 通常來說, === 的操作更簡(jiǎn)單,因?yàn)樗挥萌マD(zhuǎn)換它的操作數(shù).在不同的JavaScript引擎上,該運(yùn)算符的性能表現(xiàn)不同,但在大部分瀏覽器上,===總比==快,至少不會(huì)慢.
案例2: 比較undefined和null
使用==來比較的話,undefined和null是在一個(gè)相同的等價(jià)類上 – 他們和自己相等,同時(shí)互相之間也相等,但是不和其他任何值相等(包括那些JavaScript中的假值):
- > null == null
- true
- > undefined == null
- true
- > false == null
- false
- > 0 == null
- false
因此,下面的if語句可以檢測(cè)x是null或者是undefined(譯者注:一箭雙雕,jQuery1.81源碼中有36處地方使用了== null).
- if (x == null) {
- ...
- }
可是,代碼的簡(jiǎn)潔性完全被代碼缺少明確的意圖這一缺點(diǎn)抵消掉了: 如果需要檢測(cè)undefined值,那你還不如把它也寫上. 否則,如果一個(gè)JavaScript新手讀你的代碼,他們會(huì)覺的你只是在檢測(cè)null.如果一個(gè)老手讀你的代碼,他們也許會(huì)認(rèn)為也許是你犯了一個(gè)錯(cuò),這里應(yīng)該用的是 ===.
- if (x === undefined || x === null) {
- ...
- }
如果你的需求不是那么的嚴(yán)格,那么上面的代碼可以簡(jiǎn)寫為
- if (!x) {
- ...
- }
只要x為下面列出的這些假值,條件檢測(cè)就會(huì)通過.
- undefined
- null
- false
- 0
- ""
譯者注:5種原始值類型中,剛好各有一個(gè)假值?不對(duì),少了個(gè)NaN
案例3: 比較字符串和數(shù)字
案例場(chǎng)景是:你正在寫和用戶界面交互的代碼或者處理服務(wù)器返回參數(shù)的代碼.那么你很可能需要處理字符串類型的數(shù)字.如果x是這樣一個(gè)字符串,你可以這樣比較它:
- if (x == 123) {
- ...
- }
但是為什么不告訴讀你代碼的人x不是一個(gè)數(shù)字呢,更好的寫法是明確的將它轉(zhuǎn)換成數(shù)字再進(jìn)行比較.
- if (Number(x) === 123) {
- ...
- }
案例4: 比較對(duì)象值和原始值
使用 ==,你可以比較兩個(gè)原始值,也可以比較一個(gè)原始值和它的包裝類型對(duì)象值:
- > function isAbc(x) { return x == "abc" }
- > isAbc("abc")
- true
- > isAbc(new String("abc"))
- true
使用 === 的話,不行:
- > new String("abc") === "abc"
- false
等號(hào)左邊是一個(gè)對(duì)象值,等號(hào)右邊是一個(gè)原始值.因此,他們沒有相同的類型,也就不能嚴(yán)格相等.盡管如此,你仍然應(yīng)該優(yōu)先考慮,如何才能讓讀你代碼的人清楚的知道你這行代碼的意圖.如果用下面這個(gè)判斷的話
- x == "abc"
你想要完成的任務(wù)是什么?
左側(cè)的值真的既可能是一個(gè)字符串包裝對(duì)象又可能是一個(gè)字符串原始值嗎?這似乎不太可能,但如果真是這樣的話,你應(yīng)該在文檔中很清楚的寫明這到底是個(gè)什么樣的操作.
你是想把對(duì)象值轉(zhuǎn)換成原始值嗎? 那么你可以寫的更明確一點(diǎn)
- String(x) === "abc"
你是想要拆箱出一個(gè)原始值嗎?那么你應(yīng)該這么寫
- x.valueOf() === "abc"
案例5: JavaScript是很靈活的 – 我寫的代碼也應(yīng)該如此
這個(gè)論點(diǎn)是這樣的:我希望我的代碼能表現(xiàn)出和JavaScript同樣的靈活性.并且 == 能幫我實(shí)現(xiàn)它.下面是體現(xiàn)JavaScript靈活性的例子,它能自動(dòng)轉(zhuǎn)換值的類型:
- > "abc" + false
- 'abcfalse'
- > 3 + true
- 4
- > +"73"
- 73
下面是上述論點(diǎn)的幾個(gè)反駁:
標(biāo)準(zhǔn)的隱式轉(zhuǎn)換并不可能總是符合你的期望.例如:
- > !"false"
- false
- > 7 + "3"
- '73'
- > Number("")
- 0
寬容的相等判斷和通常見到的隱式轉(zhuǎn)換有著不同的表現(xiàn):
- > 2 == false
- false
- > 2 == true
- false
- > Boolean(2)
- true
明確的類型轉(zhuǎn)化加上嚴(yán)格的相等判斷能夠產(chǎn)生更具描述性的代碼.不好的寫法:用寬容相等來實(shí)現(xiàn)靈活性
- function is123Implicit(x) {
- return x == 123;
- }
- > is123Implicit(123)
- true
- > is123Implicit(new Number(123))
- true
- > is123Implicit("123")
- true
替代方法: 明確的類型轉(zhuǎn)換加嚴(yán)格相等實(shí)現(xiàn)靈活性:
- function is123Explicit(x) {
- x = Number(x);
- return x === 123;
- }
- > is123Explicit(123)
- true
- > is123Explicit(new Number(123))
- true
- > is123Explicit("123")
- true
誰說你的代碼必須要靈活?可以說JavaScript這種默認(rèn)的靈活性是一個(gè)bug而不是特性.編寫防御型的代碼能更快的暴露出這些bug.一個(gè)更有防御性的函數(shù)is123Explicit()如下:
- function is123Defensive(x) {
- if (typeof x !== "number") {
- throw new TypeError("Not a number: "+x);
- }
- return x === 123;
- }
如果你想傳入一個(gè)非數(shù)字原始值的參數(shù),那么你得首先進(jìn)行類型轉(zhuǎn)換.
結(jié)論
我希望我已經(jīng)說服了你,應(yīng)該堅(jiān)持以淺顯易懂為原則,堅(jiān)決不使用==來做判斷.這樣做是有道理的,不光針對(duì)新手,通常來說,代碼中有更少技巧性的東西,就意味著代碼有更好的可讀性。
原文鏈接:http://www.cnblogs.com/ziyunfei/archive/2012/09/22/2696109.html