在前端表單與電商金額計算中,經常需要使用 JavaScript 的 Math.ceil 無條件進位將帶有小數的數值向上取整。由於原生 Math.ceil() 僅支援整數進位,若要處理「無條件進位到小數點第二位」或「十位數進位」,則需結合倍率位移公式;計算完成後若需加上逗號顯示,可進一步搭配 JS 數字加逗號與轉換千分位顯示 進行格式化。
⚡ 快速跳轉(依實務情境選擇):
一、 核心複製即用範本與無條件進位公式對照表
在 JavaScript 中,Math.ceil(x) 會回傳大於或等於 x 的最小整數(朝正無限大 +∞ 方向取整)。以下整理實務開發最常使用的 4 種無條件進位情境與對應公式:
| 進位需求情境 | 計算公式寫法 | 輸入範例 | 輸出結果 |
|---|---|---|---|
| 基本整數無條件進位 | Math.ceil(num) | 9.01 | 10 |
| 負數無條件進位(朝 0 靠近) | Math.ceil(num) | -9.5 | -9 |
| 無條件進位到小數點第 2 位 | Math.ceil(num * 100) / 100 | 1.141 | 1.15 |
| 無條件進位到整數十位數 | Math.ceil(num / 10) * 10 | 123 | 130 |
二、 通用位數無條件進位函式(ceilByDigits)
為了處理 IEEE 754 浮點數運算產生的微小誤差(如 1.14 * 100 可能變成 113.99999999999999),建議在位移計算時加入 toPrecision(15) 進行修正。以下提供支援正負位數(小數點或十百千位)的通用封裝函式:
/**
* 指定位數無條件進位
* @param {number} num 原始數值
* @param {number} digits 進位到小數點第幾位 (正數為小數點後,負數為整數位)
*/
function ceilByDigits(num, digits = 0) {
const factor = Math.pow(10, digits);
// 先放大、修正浮點數誤差、進位、再縮小
return Math.ceil(Number((num * factor).toPrecision(15))) / factor;
}
// 實測範例
console.log(ceilByDigits(1.141, 2)); // 1.15 (小數點第二位)
console.log(ceilByDigits(123.45, -1)); // 130 (十位數)
console.log(ceilByDigits(123.45, -2)); // 200 (百位數)
三、 分項語法拆解與應用場景實作
1. 基本整數與正負數進位規則
Math.ceil() 的核心邏輯是「向上取整」,這在處理負數時與 Math.floor() 或 Math.trunc() 的行為不同:
- 正數:
Math.ceil(1.2)得到2。 - 負數:
Math.ceil(-1.2)得到-1(因為 -1 大於 -1.2)。
若你的需求是「不論正負,一律遠離 0 進位」(例如 -1.2 變 -2),則需判斷正負號後改用 Math.abs() 搭配 Math.ceil()。
2. 指定小數點第 N 位無條件進位與浮點數誤差防範
直接使用 num * 100 容易踩到 JavaScript 精度陷阱。例如:Math.ceil(1.14 * 100) / 100 理論上應為 1.14,但若 1.14 * 100 變成 114.00000000000001,結果會變成 1.15。
解法思路:
使用 toPrecision(15) 將數值強制轉回最接近的精確值後再進行 Math.ceil,可確保在 99.9% 的商業計算中結果正確。
3. 列表分頁總頁數計算(Pagination Total Pages)
這是 Math.ceil 最經典的應用場景。當我們從後端取得總資料筆數,並根據前端設定的每頁顯示數量時,總頁數必須無條件進位。
const totalItems = 45; // 總共有 45 筆資料
const itemsPerPage = 10; // 每頁顯示 10 筆
// 計算總頁數
const totalPages = Math.ceil(totalItems / itemsPerPage);
console.log(totalPages); // 輸出 5 (最後一頁只有 5 筆也算一頁)
在處理分頁導覽時,若需要根據當前網址參數決定起始頁面,可參考 [JS] Javascript 取得目前 URL 與相關參數(總整理) 來解析 page 參數。
四、 常見問題與排錯 Q&A
Q1:Math.ceil() 與 Math.round()、Math.floor() 有什麼差別?
- Math.ceil():無條件進位(向上取整)。
- Math.floor():無條件捨去(向下取整)。
- Math.round():四捨五入。
- Math.trunc():直接去掉小數部分(在正數時等同 floor,負數時等同 ceil)。
Q2:為什麼 Math.ceil("10.5") 可以運作?
JavaScript 會在執行 Math 方法前,自動嘗試將字串透過隱含轉型變為數字。但為了程式碼健壯性,建議先使用 Number() 進行顯式轉換,避免傳入非數字字串導致 NaN。
Q3:如何處理無條件進位後的金額格式化?
進位後的數值通常是 Number 型別,若要顯示在 UI 上並加上千分位逗號,建議使用 Intl.NumberFormat:
const price = Math.ceil(1234.5); // 1235
const formatted = new Intl.NumberFormat('zh-TW').format(price); // "1,235"
Q4:Math.ceil() 會處理 NaN 或 Infinity 嗎?
- 若傳入
NaN,結果為NaN。 - 若傳入
Infinity或-Infinity,結果維持原樣。 - 若傳入
null,會被轉為0,結果為0。
發佈留言