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