JS數量填12px也過關?別把parseInt當輸入驗證

商品數量欄位收到「12px」,程式卻照樣當成12送出?如果你用parseInt(value, 10)判斷輸入是否合法,就可能遇到這個問題。它能讀取開頭的整數部分,並不要求整個字串都是數字。

先看被截掉的是哪一段

在瀏覽器Console貼上這幾行,留意字串尾巴以及小數點之後的內容。

console.log(parseInt('12px', 10)) // 12
console.log(parseInt('12.8', 10)) // 12
console.log(parseInt('1e3', 10))  // 1
console.log(parseInt('px12', 10)) // NaN

前三個例子都能從開頭讀到數字,遇到不能當作十進位數字的字元便停止。最後一個連開頭都讀不到數字,才得到NaN。所以「結果不是NaN」只代表讀到某個整數部分,不能證明輸入符合數量欄位的要求。

先定義數量欄位接受什麼

假設購物表單接受1至99件、只允許十進位數字,不接受正負號、小數、指數或單位;前後空白可忽略,前導零也可接受。這是下面案例的規則,99不是所有網站都適用的上限。

function readQuantity(raw) {
  if (typeof raw !== 'string') return null
  const text = raw.trim()

  if (!/^[0-9]+$/.test(text)) return null
  const quantity = Number(text)

  if (!Number.isSafeInteger(quantity)) return null
  if (quantity < 1 || quantity > 99) return null
  return quantity
}

先確認整個去除前後空白後的字串都由數字組成,再轉成Number,最後核對安全整數與範圍。空字串過不了第一道格式檢查,「12px」也不能只靠開頭的12過關。null表示拒絕輸入,別把它再轉成0送出。

這個函式要接收輸入框的字串value。如果你改用已轉成數字的資料,或要接受小數與正負號,就應重新定義規則,不能直接照搬這個格式檢查。

用幾個容易漏掉的值試一次

先貼上完整函式,再貼下面的呼叫。函式名稱相同時不要在同一測試檔重複宣告多份。

for (const raw of [
  '12', ' 12 ', '012', '12px', '12.8',
  '1e3', '', '   ', '0', '100', '+12'
]) {
  console.log(JSON.stringify(raw), readQuantity(raw))
}

依這組規則,前三項回傳12,其餘回傳null。若你不允許「012」這類前導零,也要把它寫進格式規則與測試,而不是期待轉成數字後仍保留原樣。

換成Number也不能省掉格式規則

Number('12px')會得到NaN,但它接受的格式不只一般十進位數字字串,空字串也有特別的轉換結果。

console.log(Number(''))     // 0
console.log(Number('   '))  // 0
console.log(Number('1e3'))   // 1000
console.log(Number('0x10'))  // 16

如果欄位只接受一般數量,把parseInt換成Number再檢查範圍,仍可能讓不想接受的格式通過。先查完整字串,再轉換,才能把「轉換得出數字」與「符合表單規格」分清。

前端提示之外,伺服器還要再驗證

前端檢查適合即時提醒使用者修改輸入;伺服器收到請求後仍要按照同一業務規則核對數量、範圍及可購庫存。使用者可以繞過頁面直接送請求,不能把前端函式當作訂單成立的唯一依據。

商品編號、電話或帶前導零的識別碼,也不一定適合轉成數字。先問這個欄位是否真的要做算術:若只是識別或顯示,保留字串往往更合適。超出安全整數範圍的資料也不能靠parseInt保證精度。

參考資料

原文鏈接:https://wntheme.com/js-parseint-quantity-validation/,轉載請註明出處。
0

評論0

顯示驗證碼
沒有帳號?註冊  忘記密碼?