- 原文地址:dev.to/promhize/wh…
前幾天忽然發現github上有一個大熱門專案 —— “33 concepts every JavaScript developer should know”,目前已經將近25000個Stars。這個專案旨在幫助前端開發者掌握33個JavaScript基礎概念。按作者話說,這些概念並不是開發所必需的,但它們是引導你通向前端大牛之路的基石。
遺憾的是,該專案中文版的文章收錄不盡完整。所以本著學習與交流的目的,本人會把33個概念所涉及的文章利用業餘時間竭盡所能的翻譯出來,其中不免疏漏,望請指正。本文是第四篇,以下為正文:
隱式轉型是指,JavaScript會把一個非預期值轉換為預期值。
什麼意思呢?
在一定條件下,你能夠把一個字串當作數值使用,也能夠把一個物件當作字串使用,這些型別能夠發生轉換,以滿足你的預期。然而,我們應儘量避免JavaScript的這一語言特性。
3 * "3" //9
1 + "2" + 1 //121
true + true //2
10 - true //9
const foo = {
valueOf: () => 2
}
3 + foo // 5
4 * foo // 8
const bar = {
toString: () => " promise is a boy :)"
}
1 + bar // "1 promise is a boy :)"
4 * [] // 0
4 * [2] // 8
4 + [2] // "42"
4 + [1, 2] // "41,2"
4 * [1, 2] // NaN
"string" ? 4 : 1 // 4
undefined ? 4 : 1 // 1
複製程式碼
數字表示式中的非數值
字串
當一個字串參與到數學運算中來時,如涉及以下四種運算:-
、*
、/
、%
,則相當於為該字串呼叫了內建的Number()
函式。這很容易理解,任何包含數字的字串都會轉換為數字,對於含有非數字字元的,則返回NaN
,具體參考Number()
轉換規則。示例如下:
3 * "3" // 3 * 3
3 * Number("3") // 3 * 3
Number("5") // 5
Number("1.") // 1
Number("1.34") // 1.34
Number("0") // 0
Number("012") // 12
Number("1,") // NaN
Number("1+1") // NaN
Number("1a") // NaN
Number("one") // NaN
Number("text") // NaN
複製程式碼
“+
”操作符是個例外
不像其它數學運算子,“+
”表現出兩種特性:
- 加法
- 字串拼接
字串參與“+
”操作時,JavaScript不再把字串轉為數字,反會將數字轉為字串。
// 字串拼接
1 + "2" // "12"
1 + "js" // "1js"
// 加法運算
1 + 2 // 3
1 + 2 + 1 // 4
// 先加法,再拼接
1 + 2 + "1" // "31"
(1 + 2) + "1" // "31"
// 全部拼接
1 + "2" + 1 // "121"
(1 + "2") + 1 // "121"
複製程式碼
物件
JavaScript中大多數物件都會轉換為“[object Object]”,比如:
"name" + {} // "name[object Object]
複製程式碼
每個JavaScript都會繼承toString()
方法,這就說明無論何時,物件度能夠被轉換為字串。接下來,toString()
方法的返回值就會參與到字串拼接和數學運算中去。
const foo = {}
foo.toString() // [object Object]
const baz = {
toString: () => "I'm object baz"
}
baz + "!" // "I'm object baz!"
複製程式碼
物件參與數學運算時,JavaScript會試圖將它的返回值轉換為數字;字串拼接時,則轉換為字串。
const foo = {
toString: () => 4
}
2 * foo // 8
2 / foo // 0.5
2 + foo // 6
"four" + foo // "four4"
const baz = {
toString: () => "four"
}
2 * baz // NaN
2 + baz // 2four
const bar = {
toString: () => "2"
}
2 + bar // "22"
2 * bar // 4
複製程式碼
陣列
陣列同樣繼承了toString()
方法,然而在工作方式上則略有不同,轉換的過程相當於為陣列呼叫了一個沒傳參的join()
方法。
[1,2,3].toString() // "1,2,3"
[1,2,3].join() // "1,2,3"
[].toString() // ""
[].join() // ""
"me" + [1,2,3] // "me1,2,3"
4 + [1,2,3] // "41,2,3"
4 * [1,2,3] // NaN
複製程式碼
當你把陣列當作字串使用時,JavaScript會將toString()
的返回值和另一個值拼接起來;當作數字使用時,返回值則轉換為數字。
4 * [] // 0
4 / [2] // 2
// 相當於
4 * Number([].toString())
4 * Number("")
4 * 0
//
4 / Number([2].toString())
4 / Number("2")
4 / 2
複製程式碼
True, False 和 ""
Number(true) // 1
Number(false) // 0
Number("") // 0
4 + true // 5
3 * false // 0
3 * "" // 0
3 + "" // "3"
複製程式碼
The valueOf()
method```
在JavaScript中,你同樣可以定義一個valueOf()
方法,它也可以將物件轉換為字串或數值。
const foo = {
valueOf: () => 3
}
3 + foo // 6
3 * foo // 9
複製程式碼
當toString()
和valueOf()
方法同時在物件中出現時,JavaScript會優先呼叫valueOf
方法。
const bar = {
toString: () => 2,
valueOf: () => 5
}
"sa" + bar // "sa5"
3 * bar // 15
2 + bar // 7
複製程式碼
真和假
JavaScript中的每個值都可以轉換為true
和false
。轉換為true
意味著該值為真,反之則為假。
其中有為數不多的值會被轉換為false
,它們是:
- false
- 0
- null
- undefined
- NaN
- -0
除此以外,所有值都為真。
if (-1) // truthy
if ("0") // truthy
if ({}) // truthy
複製程式碼
上面的程式碼正如我們所預期,但是在實踐中我們仍應該顯式的確定一個值是否為真。總體上,我們應當避免使用隱式轉型,即便你認為已將它爛熟於胸了。
下面的程式碼才是你應該參考使用的:
if (counter === 2)
//or
if (typeof counter === "number")
複製程式碼
假如,你定義了一個處理數字的函式。
const add = (number) => {
if (!number) new Error("Only accepts arguments of type: number")
//your code
}
複製程式碼
當你呼叫這個函式,並想傳入引數 0
時,函式會給你丟擲一個錯誤。
add(0) // Error: Only accepts arguments of type: number
// 更好的嘗試
const add = (number) => {
if (typeof number !== "number") new Error("只接受數字型別: number")
//your code
}
add(0) // 這下沒錯了
複製程式碼
NaN
NaN
是一個特殊的數值,它與任何值都不相等,包括 NaN
本身
NaN === NaN // false
const notANumber = 3 * "a" // NaN
notANumber == notANumber // false
notANumber === notANumber // false
複製程式碼
NaN
是JavaScript中唯一一個自己不等於自己的值,你可以利用這個特性來檢查NaN
if (notANumber !== notANumber) // true
複製程式碼
ES6標準引進了一種用來檢查 NaN
的新方法 Number.isNaN
。
Number.isNaN(NaN) // true
Number.isNaN("name") // false
複製程式碼
使用這個函式時需要注意,它會首先將引數轉型,然後才開始檢查 NaN
,示例如下:
const coerceThenCheckNaN = (val) => {
const coercedVal = Number(val)
return coercedVal !== coercedVal ? true : false
}
coerceThenCheckNaN("1a") // true
coerceThenCheckNaN("1") // false
coerceThenCheckNaN("as") // true
coerceThenCheckNaN(NaN) // true
coerceThenCheckNaN(10) // false
複製程式碼
(完)
下一篇講述相等操作符和全等操作符,敬請期待