JavaScript 課程 – 數學與數字處理(Math & Numbers)
主題:Math 物件
簡介
在日常的前端開發或 Node.js 後端程式中,數值運算、隨機產生、以及角度、時間的轉換都是常見需求。
雖然 JavaScript 內建的算術運算子(+、-、*、/、%)足以處理簡單的加減乘除,但面對更複雜的需求時,我們就需要依賴 全域的 Math 物件。
Math 提供了一組 靜態方法(不需要實例化)與 常數,涵蓋了三角函數、指數與對數、四捨五入、隨機數產生等功能。掌握它不僅能讓程式碼更簡潔,也能提升計算的正確性與效能,是每位 JavaScript 開發者的必備工具。
核心概念
1. Math 常數
| 常數 | 說明 | 範例 |
|---|---|---|
Math.PI |
圓周率 π(約 3.14159) | Math.PI * radius ** 2 計算圓面積 |
Math.E |
自然常數 e(約 2.71828) | Math.pow(Math.E, x) 計算 e 的 x 次方 |
Math.LN2、Math.LN10、Math.LOG2E、Math.LOG10E |
各種對數基底的常數 | Math.log2(8) === Math.LOG2E * Math.log(8) |
小技巧:直接使用常數比手寫數值更安全,避免因四捨五入誤差造成的計算偏差。
2. 基本數學函式
| 方法 | 功能 | 範例 |
|---|---|---|
Math.abs(x) |
取絕對值 | Math.abs(-5) // 5 |
Math.max(...values) |
取得最大值 | Math.max(3, 9, -2) // 9 |
Math.min(...values) |
取得最小值 | Math.min(3, 9, -2) // -2 |
Math.round(x) |
四捨五入到最接近的整數 | Math.round(4.6) // 5 |
Math.floor(x) |
向下取整 | Math.floor(4.9) // 4 |
Math.ceil(x) |
向上取整 | Math.ceil(4.1) // 5 |
Math.trunc(x) |
去除小數部分(不四捨五入) | Math.trunc(4.9) // 4 |
3. 高階函式
| 方法 | 功能 | 範例 |
|---|---|---|
Math.pow(base, exponent) |
計算 base 的 exponent 次方 |
Math.pow(2, 3) // 8 |
Math.sqrt(x) |
開根號 | Math.sqrt(16) // 4 |
Math.cbrt(x) |
立方根 | Math.cbrt(27) // 3 |
Math.hypot(...values) |
計算歐幾里得距離(向量長度) | Math.hypot(3,4) // 5 |
Math.sin/Math.cos/Math.tan(x) |
三角函數(參數必為弧度) | Math.sin(Math.PI/2) // 1 |
Math.asin/Math.acos/Math.atan(x) |
反三角函數,回傳弧度 | Math.acos(0) // Math.PI/2 |
Math.log(x) |
自然對數(底 e) | Math.log(Math.E) // 1 |
Math.log10(x)、Math.log2(x) |
常用底 10、2 的對數 | Math.log10(100) // 2 |
4. 隨機數
Math.random()會回傳 0(含)到 1(不含) 之間的浮點數。- 常見的「產生區間隨機整數」寫法如下:
/**
* 產生 min ~ max(含)之間的隨機整數
* @param {number} min 最小值(含)
* @param {number} max 最大值(含)
* @returns {number}
*/
function randInt(min, max) {
// 先確保 min <= max,若傳入相反值則自動交換
if (min > max) [min, max] = [max, min];
// Math.random() * (max - min + 1) 產生 [0, max-min+1) 的浮點數
// 再加上 min,最後取整數
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// 範例:產生 1~100 的隨機整數
console.log(randInt(1, 100));
程式碼範例
下面提供 5 個實務上常用的範例,每個範例都附有說明與註解,讓你快速上手 Math 物件的各種功能。
範例 1:計算圓的面積與周長
/**
* 計算圓的面積與周長
* @param {number} radius 半徑
* @returns {{area:number, circumference:number}}
*/
function circle(radius) {
// 使用 Math.PI 取得更精確的圓周率
const area = Math.PI * Math.pow(radius, 2); // πr²
const circumference = 2 * Math.PI * radius; // 2πr
return { area, circumference };
}
console.log(circle(5));
// => { area: 78.53981633974483, circumference: 31.41592653589793 }
為什麼使用
Math.pow而不是radius ** 2?
兩者在 ES6+ 都可以,但在舊版瀏覽器(IE)仍需Math.pow,同時可保持語意一致。
範例 2:將角度 (Degree) 轉為弧度 (Radian) 並計算 sin、cos
/**
* 角度轉弧度
* @param {number} deg 角度值
* @returns {number} 弧度值
*/
function degToRad(deg) {
return deg * (Math.PI / 180);
}
/**
* 計算 sin、cos、tan(接受角度參數)
* @param {number} deg 角度
* @returns {{sin:number, cos:number, tan:number}}
*/
function trigFromDegree(deg) {
const rad = degToRad(deg);
return {
sin: Math.sin(rad),
cos: Math.cos(rad),
tan: Math.tan(rad)
};
}
console.log(trigFromDegree(45));
// => { sin: 0.7071067811865475, cos: 0.7071067811865476, tan: 0.9999999999999999 }
小技巧:
Math.tan(90°)會因為弧度值無法精確表示而回傳極大數值,實務上若需要判斷垂直,可先檢查Math.abs(cos) < Number.EPSILON。
範例 3:四捨五入到指定小數位
/**
* 四捨五入到 n 位小數
* @param {number} value 原始數值
* @param {number} digits 保留的小數位數
* @returns {number}
*/
function roundTo(value, digits) {
const factor = Math.pow(10, digits);
// 先乘以 factor,四捨五入後再除回去
return Math.round(value * factor) / factor;
}
console.log(roundTo(3.1415926, 2)); // 3.14
console.log(roundTo(1.005, 2)); // 1.01 (避免浮點誤差)
為什麼要使用
Math.pow(10, digits)?
直接寫10 ** digits也行,但Math.pow在舊環境相容性更好。
範例 4:找出一組數字中的最大公因數 (GCD)
/**
* 計算兩個正整數的最大公因數(Euclidean algorithm)
* @param {number} a
* @param {number} b
* @returns {number}
*/
function gcd(a, b) {
// 確保 a、b 為正整數
a = Math.abs(a);
b = Math.abs(b);
while (b !== 0) {
const temp = b;
b = a % b; // 取餘數
a = temp;
}
return a;
}
/**
* 計算任意長度陣列的 GCD
* @param {number[]} nums
* @returns {number}
*/
function arrayGCD(nums) {
return nums.reduce((prev, cur) => gcd(prev, cur));
}
console.log(arrayGCD([48, 64, 80])); // 16
說明:
%(取餘)是唯一需要「手動」使用的算術運算子;其餘的邏輯全部由Math協助完成。
範例 5:產生隨機顏色(HEX)
/**
* 產生隨機 HEX 顏色字串,例如 "#3FA9C4"
* @returns {string}
*/
function randomHexColor() {
// Math.random() 產生 0~1,* 0xFFFFFF 取得 0~16777215
const num = Math.floor(Math.random() * 0xFFFFFF);
// 轉成 16 進位字串,padStart 確保六位
const hex = num.toString(16).padStart(6, '0');
return `#${hex}`;
}
console.log(randomHexColor()); // 例: "#a1b2c3"
實務應用:在圖表、遊戲或 UI 主題切換時,快速產生不重複的色彩。
常見陷阱與最佳實踐
| 陷阱 | 說明 | 最佳做法 |
|---|---|---|
| 浮點數精度問題 | 例如 0.1 + 0.2 !== 0.3 |
使用 Number.EPSILON 或先乘除整數後再除回來(如範例 3) |
| 角度與弧度混用 | Math.sin(90) 會把 90 當作弧度,結果錯誤 |
統一使用弧度或建立 degToRad/radToDeg 輔助函式 |
Math.random() 的分布不均 |
直接取 Math.random()*N 再 Math.floor 會產生 [0,N-1] 的均勻分布,但 不適用於加密 |
若需安全隨機,使用 crypto.getRandomValues(瀏覽器)或 crypto.randomInt(Node) |
忘記 Math 是靜態物件 |
不能 new Math(),也不會有 this 相關概念 |
直接以 Math.xxx 調用 |
對 NaN、Infinity 的處理 |
Math.max(NaN, 5) => NaN |
使用 Number.isNaN 檢查或先過濾陣列 |
其他最佳實踐
- 封裝常用計算:將常見的「角度轉弧度」或「四捨五入」寫成工具函式,提升可讀性。
- 避免硬編碼常數:如
3.14159改用Math.PI,避免因精度差異產生 bug。 - 使用
Number.isFinite保障輸入:在接受外部數值(例如 API 回傳)時,先檢查是否為有限數字。 - 對大數運算考慮
BigInt:Math不支援BigInt,若需要超過Number.MAX_SAFE_INTEGER,改用自訂演算法或第三方函式庫。
實際應用場景
| 場景 | 需求 | 使用的 Math 方法 |
|---|---|---|
| 資料視覺化(Chart.js、D3) | 計算座標、縮放比例、角度 | Math.max/min, Math.sin/cos, Math.round |
| 遊戲開發(Canvas、WebGL) | 產生隨機敵人位置、碰撞檢測 | Math.random, Math.hypot, Math.floor |
| 金融系統 | 四捨五入到分(2 位小數)或千分位 | Math.round, Number.EPSILON |
| 密碼學相關 UI | 產生隨機驗證碼顏色 | Math.random, toString(16) |
| 科學計算(統計、機器學習) | 計算標準差、指數衰減 | Math.sqrt, Math.exp(Math.pow(Math.E, x)) |
案例說明:假設我們在一個線上投票系統,需要根據投票比例即時顯示圓形圖的扇形角度。利用
Math.PI * 2 * (voteCount / total)計算弧度,再配合Math.sin/Math.cos產生座標,即可在 Canvas 上繪製正確的扇形。
總結
Math 物件是 JavaScript 標準庫中最常被使用、也是最基礎的工具之一。掌握它的 常數、基本函式與高階函式,不僅能讓你在日常開發中寫出更簡潔、正確的程式碼,還能避免常見的浮點誤差與角度混淆等陷阱。
- 常數(
Math.PI、Math.E)提供精確的基礎值。 - 基本函式(
abs、max、min、round)是日常四則運算的好幫手。 - 高階函式(
sin、cos、log、hypot)讓複雜的科學計算變得輕鬆。 - 隨機數(
Math.random)配合簡單的區間函式,可快速產生測試資料或 UI 效果。
在實務開發中,建議 將常用的 Math 包裝成工具函式,並遵守「避免硬編碼、檢查輸入、注意浮點精度」的最佳實踐。如此一來,無論是前端圖表、後端統計模型,或是遊戲畫面渲染,都能夠以最少的程式碼達成正確且高效的數學運算。
祝你在 JavaScript 的數學世界中玩得開心,寫出更穩定、更易讀的程式碼! 🚀