為什么在JavaScript中['1', '5', '11'].map(parseInt) 返回 [1, NaN, 3]
他接下來看到的東西震驚了他:
這怎么可能呢?parseInt是不是壞了? map() 是不是有bug?
他驚慌地抬頭看,引來了Jake尖銳而令人不安的笑聲。
Alex自稱編程高手,以快速編碼和簡(jiǎn)潔代碼為傲。
盡管剛進(jìn)入這個(gè)行業(yè)不久,他總是認(rèn)為自己比團(tuán)隊(duì)其他人都強(qiáng),固執(zhí)地我行我素;所有善意的建議都被他當(dāng)耳邊風(fēng)。
但Alex很快就要遭遇災(zāi)難性的失敗了。這將是一次痛苦而令人謙卑的經(jīng)歷,他永遠(yuǎn)不會(huì)忘記。
一切都始于Alex和Cody被分配了一個(gè)項(xiàng)目任務(wù)。要讓用戶查看團(tuán)隊(duì)一直在開發(fā)的電子商務(wù)網(wǎng)站上的產(chǎn)品。
他們?nèi)蕴幱趧?chuàng)業(yè)階段,所有數(shù)據(jù)都存儲(chǔ)和更新在CSV文件中。
產(chǎn)品名稱、價(jià)格、數(shù)量...所有你在亞馬遜等網(wǎng)站上能看到的常見信息。
當(dāng)Alex得知要合作時(shí),他傲慢地嗤之以鼻。
"我不需要和任何人合作,好嗎?"他一邊在電腦上打字,一邊對(duì)善良的工程主管Jake冷笑道。"這簡(jiǎn)直就是從數(shù)據(jù)庫(kù)獲取數(shù)據(jù)然后在JSX中顯示而已"。
"Alex,你需要學(xué)會(huì)與他人合作,我一直在告訴你這一點(diǎn)。"Jake帶著耐心而勉強(qiáng)的微笑回應(yīng)道。他已經(jīng)習(xí)慣了這個(gè)人自我中心的行為。
"我不需要和任何人合作,我自己就能搞定。Cody只會(huì)用他那些關(guān)于可讀性代碼的廢話拖我后腿。"
"Cody是我們最優(yōu)秀的員工之一,他花時(shí)間是有原因的。我一直在告訴你,編碼并不只是快速或簡(jiǎn)潔地寫代碼..."
"你總是對(duì)我說教,但你從不聽我的。這次我只想一個(gè)人工作,行嗎?" "拜托?"Alex迅速補(bǔ)充道,以避免聽起來太粗魯 - 當(dāng)然,臉上仍帶著那種傲慢的笑容。
Jake嘆了口氣。
"好吧,如果你能將這個(gè)字符串?dāng)?shù)組轉(zhuǎn)換成相同的數(shù)字?jǐn)?shù)組,我就讓你一個(gè)人工作。"他一邊說一邊在旁邊的紙上寫道。
Alex簡(jiǎn)直不敢相信。紙上是一個(gè)簡(jiǎn)單的數(shù)組。
['1', '5', '11']
這一定是個(gè)陷阱問題。他懷疑地抬頭看著Jake。
"認(rèn)真的嗎?你覺得我蠢到連這個(gè)都解析不了嗎?"
"試試看,你只有一次機(jī)會(huì)。"Jake對(duì)這個(gè)年輕人表現(xiàn)出驚人的耐心,他應(yīng)該得到一枚自制力勛章。
Alex帶著得意的表情,打開了一個(gè)新的VS Code終端,傲慢地輸入了看似顯而易見的Node解決方案:
['1', '5', '11'].map(parseInt)
他得意洋洋地笑了,轉(zhuǎn)身卻看到Jake臉上帶著了然的微笑 - 他立刻失去了平衡。
"你確定嗎Alex?為什么不按Enter鍵,讓我們看看實(shí)際的結(jié)果數(shù)組是什么。"
有點(diǎn)不確定的他,在最后時(shí)刻掃視了一遍簡(jiǎn)短的CLI代碼以確保萬無一失。
他接下來看到的東西震驚了他的內(nèi)心。
這怎么可能呢? parseInt 是不是壞了? map() 是不是有bug?
他驚慌地抬頭看,引來了Jake尖銳而令人不安的笑聲。
"Alex,你被解雇了。"
"什么?!"Alex尖叫道。
"在我閉上眼睛又睜開之前收拾東西滾出去,你這個(gè)傲慢的蠢貨!"
你看,Alex的失敗并不是因?yàn)樗焕斫?nbsp;map 和 parseInt -- 盡管理解它們本可以幫到他。
而是因?yàn)樗V迷于使代碼盡可能簡(jiǎn)短,以犧牲可讀性和清晰度為代價(jià)...
事實(shí)上,在99%的情況下,我們是這樣使用 map 和 parseInt 的:
const doubles = ['1', '5', '11'].map((num) => num * 2);
console.log(doubles); // [2, 10, 22]
const num = parseInt('5');
console.log(num); // ?? 5 -- not NaN!
但是當(dāng)你使用 map 和 console.log 時(shí),你可能會(huì)對(duì)結(jié)果感到震驚:
const doubles = ['1', '2', '3'].map(console.log);
它為每個(gè)項(xiàng)目記錄了3對(duì)數(shù)字!
這是因?yàn)?nbsp;map() 回調(diào)實(shí)際上接受3個(gè)參數(shù):
所以你實(shí)際上是用3個(gè)參數(shù)調(diào)用 parseInt :
// parseInt take 2 args max but JS compiler doesn't complain
['1', '5', '11'].map(parseInt)
// parseInt('1', '0', ['1', '5', '11'])
// parseInt('5', '1', ['1', '5', '11'])
// parseInt('11', '2', ['1', '5', '11'])
Alex從不知道 parseInt 接受1個(gè)或2個(gè)參數(shù),并且對(duì)每種情況的行為都不同:
當(dāng)有第二個(gè)參數(shù)時(shí),它成為第一個(gè)數(shù)字參數(shù)的基數(shù):
// ?? invalid positive number, ignore
parseInt('1', '0'); // 1 ?
parseInt('3', 'blah blah'); // 3
// ?? invalid base (1)
parseInt('2', '1'); // NaN
parseInt('5', '1'); // NaN ?
// ?? '10' is 2 in base 2 (remember?)
parseInt('10', '2'); // 2
parseInt('11', '2'); // 3 ?
盡管他對(duì) map 和 parseInt 的知識(shí)一般,但只要更加明確,他本可以避免所有這些問題:
['1', '5', '11'].map((num) => parseInt(num));
縮短代碼可能有利于減少混亂,但我們應(yīng)該始終優(yōu)先考慮清晰和可讀的代碼:
特別是當(dāng)增加的長(zhǎng)度并不是什么大問題時(shí),你知道嗎?
async function setTimeout() {
// ?
await new Promise((resolve) => setTimeout(resolve, 1000));
console.log('Coding Beauty');
}
async function setTimeout() {
// ?
await new Promise((resolve) => setTimeout(() => resolve(), 1000));
console.log('Coding Beauty');
}