Math 是 JavaScript 内置的一个全局对象,它提供了各种数学常数和函数。注意:Math 不是构造函数 ,你不能使用 new Math() 来创建实例,所有属性和方法都是静态的,直接通过 Math.属性名 或 Math.方法名() 调用。
javascript
// ❌ 错误用法
const math = new Math();
// ✅ 正确用法
Math.PI; // 访问常量
Math.random(); // 调用方法
常用数学常量
Math 对象提供了一些常用的数学常量:
| 常量 | 说明 | 值 |
|---|---|---|
Math.PI |
圆周率 π | 3.141592653589793 |
Math.E |
自然对数的底数 e | 2.718281828459045 |
Math.LN2 |
2 的自然对数 | 0.6931471805599453 |
Math.LN10 |
10 的自然对数 | 2.302585092994046 |
Math.SQRT2 |
2 的平方根 | 1.4142135623730951 |
使用示例:
javascript
// 计算圆的面积
function circleArea(radius) {
return Math.PI * radius * radius;
}
console.log(circleArea(5)); // 78.53981633974483
常用数学方法
取整相关
1. Math.ceil() - 向上取整
返回大于或等于给定数字的最小整数(向正无穷方向舍入)。
javascript
Math.ceil(4.1); // 5
Math.ceil(4.9); // 5
Math.ceil(-4.1); // -4
Math.ceil(4); // 4
应用场景: 计算文件分片数量时,即使最后一块不满,也需要单独作为一个分片。
javascript
// 文件大小 1025 bytes,每片 1024 bytes
const fileSize = 1025;
const chunkSize = 1024;
const totalChunks = Math.ceil(fileSize / chunkSize); // 2 个分片
2. Math.floor() - 向下取整
返回小于或等于给定数字的最大整数(向负无穷方向舍入)。
javascript
Math.floor(4.1); // 4
Math.floor(4.9); // 4
Math.floor(-4.1); // -5
Math.floor(4); // 4
应用场景: 将秒数转换为分钟和秒。
javascript
const durationInSeconds = 125;
const minutes = Math.floor(durationInSeconds / 60); // 2 分钟
const seconds = durationInSeconds % 60; // 5 秒
console.log(`${minutes}:${seconds}`); // "2:5"
3. Math.round() - 四舍五入
返回最接近给定数字的整数(遵循四舍五入规则)。
javascript
Math.round(4.4); // 4
Math.round(4.5); // 5
Math.round(4.6); // 5
Math.round(-4.5); // -4 (注意:-4.5 四舍五入为 -4)
应用场景: 视频时长显示时进行四舍五入。
javascript
const videoDuration = 125.7;
const roundedDuration = Math.round(videoDuration); // 126 秒
4. Math.trunc() - 截断小数部分
移除数字的小数部分,只保留整数部分(不四舍五入)。
javascript
Math.trunc(4.9); // 4
Math.trunc(-4.9); // -4
Math.trunc(4.1); // 4
区别对比:
javascriptMath.floor(-4.5); // -5 (向下取整) Math.trunc(-4.5); // -4 (截断小数)
最值相关
1. Math.max() - 最大值
返回一组数字中的最大值。
javascript
Math.max(1, 5, 3, 9, 2); // 9
Math.max(-1, -5, -3); // -1
// 从数组中获取最大值
const numbers = [1, 5, 3, 9, 2];
Math.max(...numbers); // 9
应用场景: 确保滚动位置不小于 0。
javascript
// 防止向左滚动超出边界
const scrollLeft = Math.max(0, scrollX - 200);
2. Math.min() - 最小值
返回一组数字中的最小值。
javascript
Math.min(1, 5, 3, 9, 2); // 1
Math.min(-1, -5, -3); // -5
// 从数组中获取最小值
const numbers = [1, 5, 3, 9, 2];
Math.min(...numbers); // 1
应用场景: 限制读取的文件字节范围不超过文件总大小。
javascript
const start = 0;
const chunkSize = 1024;
const fileSize = 500;
const end = Math.min(start + chunkSize, fileSize); // 500(不会超出文件大小)
随机数
Math.random() - 生成随机数
返回一个介于 0(包含)和 1(不包含)之间的伪随机浮点数。
javascript
Math.random(); // 例如:0.7234567890123456
常用技巧:
javascript
// 生成 0 到 n-1 之间的随机整数
const randomInt = Math.floor(Math.random() * 10); // 0-9
// 生成 min 到 max 之间的随机整数(包含 min 和 max)
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
getRandomInt(1, 100); // 1-100 之间的随机整数
// 生成随机颜色
function getRandomColor() {
const r = Math.floor(Math.random() * 256);
const g = Math.floor(Math.random() * 256);
const b = Math.floor(Math.random() * 256);
return `rgb(${r}, ${g}, ${b})`;
}
幂运算与开方
1. Math.pow() - 幂运算
返回底数的指数次幂。
javascript
Math.pow(2, 3); // 8 (2³)
Math.pow(5, 2); // 25 (5²)
Math.pow(2, -1); // 0.5 (2⁻¹)
// ES6 推荐使用指数运算符 **
2 ** 3; // 8
2. Math.sqrt() - 平方根
返回一个数的平方根。
javascript
Math.sqrt(9); // 3
Math.sqrt(2); // 1.4142135623730951
Math.sqrt(-1); // NaN(负数没有实数平方根)
应用场景: 计算两点之间的距离。
javascript
function distance(x1, y1, x2, y2) {
return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
}
distance(0, 0, 3, 4); // 5
绝对值
Math.abs() - 绝对值
返回一个数的绝对值(非负值)。
javascript
Math.abs(5); // 5
Math.abs(-5); // 5
Math.abs(0); // 0
Math.abs(-3.14); // 3.14
应用场景: 计算差值的绝对值,不考虑正负。
javascript
// 计算两个时间的差值(毫秒)
const timeDiff = Math.abs(timestamp1 - timestamp2);
实际应用场景
文件分片上传
在前端大文件上传场景中,需要将文件分割成多个小块进行上传:
javascript
/**
* 将文件分割成多个 chunk
* @param {File} file - 要上传的文件
* @param {number} chunkSize - 每个分片的大小(字节)
* @returns {Array} 分片数组
*/
function splitFileIntoChunks(file, chunkSize = 1024 * 1024) {
// 默认 1MB
const totalChunks = Math.ceil(file.size / chunkSize);
const chunks = [];
for (let i = 0; i < totalChunks; i++) {
const start = i * chunkSize;
const end = Math.min(start + chunkSize, file.size);
const chunk = file.slice(start, end);
chunks.push({
index: i,
blob: chunk,
size: chunk.size,
});
}
return chunks;
}
// 使用示例
const file = document.querySelector('input[type="file"]').files[0];
const chunks = splitFileIntoChunks(file, 2 * 1024 * 1024); // 2MB 每片
console.log(`文件将被分成 ${chunks.length} 个分片`);
关键点:
- 使用
Math.ceil()确保即使最后一个分片不满,也会被计入 - 使用
Math.min()确保最后一个分片不会超出文件总大小
时间格式化
将时间戳或秒数转换为可读的时间格式:
javascript
/**
* 将秒数转换为 "mm:ss" 格式
* @param {number} seconds - 秒数
* @returns {string} 格式化后的时间字符串
*/
function formatTime(seconds) {
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${mins.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}`;
}
// 使用示例
console.log(formatTime(125)); // "02:05"
console.log(formatTime(65)); // "01:05"
console.log(formatTime(3661)); // "61:01"
更复杂的时间格式化:
javascript
/**
* 将秒数转换为 "hh:mm:ss" 格式
*/
function formatTimeHMS(seconds) {
const hours = Math.floor(seconds / 3600);
const mins = Math.floor((seconds % 3600) / 60);
const secs = Math.floor(seconds % 60);
if (hours > 0) {
return `${hours}:${mins.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}`;
}
return `${mins}:${secs.toString().padStart(2, "0")}`;
}
console.log(formatTimeHMS(3661)); // "1:01:01"
console.log(formatTimeHMS(125)); // "2:05"
视频时长转换
处理视频元数据时,经常需要转换时长格式:
javascript
/**
* 将视频时长(秒)转换为人类可读的格式
* @param {number} durationInSeconds - 视频时长(秒)
* @returns {string} 格式化后的时长
*/
function formatVideoDuration(durationInSeconds) {
const duration = Math.round(durationInSeconds); // 四舍五入
const minutes = Math.floor(duration / 60);
const seconds = duration % 60;
if (minutes >= 60) {
const hours = Math.floor(minutes / 60);
const remainingMinutes = minutes % 60;
return `${hours}:${remainingMinutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
}
return `${minutes}:${seconds.toString().padStart(2, "0")}`;
}
// 使用示例
console.log(formatVideoDuration(125.7)); // "2:06"
console.log(formatVideoDuration(3661.3)); // "1:01:01"
console.log(formatVideoDuration(59.4)); // "1:00"
滚动位置计算
在处理页面滚动、元素定位时,需要确保坐标值在合理范围内:
javascript
/**
* 计算安全的滚动位置
* @param {number} currentScroll - 当前滚动位置
* @param {number} offset - 偏移量
* @param {number} maxScroll - 最大可滚动距离
* @returns {number} 安全的滚动位置
*/
function getSafeScrollPosition(currentScroll, offset, maxScroll) {
const targetScroll = currentScroll + offset;
// 确保滚动位置在 0 到 maxScroll 之间
return Math.max(0, Math.min(targetScroll, maxScroll));
}
// 使用示例
const currentScrollX = 500;
const scrollOffset = -200;
const maxScrollX = 1000;
const safeScroll = getSafeScrollPosition(
currentScrollX,
scrollOffset,
maxScrollX,
);
console.log(safeScroll); // 300
// 边界情况
console.log(getSafeScrollPosition(100, -200, 1000)); // 0(不会小于 0)
console.log(getSafeScrollPosition(900, 200, 1000)); // 1000(不会超过最大值)
实际项目中的应用:
javascript
// 在标签页组件中,确保滚动不会超出左边界
const leftPosition = Math.max(0, scrollX - 200);
// 计算元素是否在可视区域内
function isElementInViewport(element) {
const rect = element.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= window.innerHeight &&
rect.right <= window.innerWidth
);
}
其他常见场景
1. 百分比计算
javascript
// 计算上传进度百分比
function calculateProgress(bytesUploaded, bytesTotal) {
if (!bytesTotal || bytesTotal === 0) return 0;
return Math.round((bytesUploaded / bytesTotal) * 100);
}
console.log(calculateProgress(50, 100)); // 50
console.log(calculateProgress(1, 3)); // 33
2. 限制数值范围
javascript
/**
* 将数值限制在指定范围内
* @param {number} value - 要限制的数值
* @param {number} min - 最小值
* @param {number} max - 最大值
* @returns {number} 限制后的数值
*/
function clamp(value, min, max) {
return Math.max(min, Math.min(value, max));
}
// 使用示例
clamp(150, 0, 100); // 100
clamp(-50, 0, 100); // 0
clamp(50, 0, 100); // 50
clamp(0.75, 0, 1); // 0.75
3. 相对时间显示
javascript
/**
* 将时间差转换为相对时间描述
* @param {number} diffSeconds - 时间差(秒)
* @returns {string} 相对时间描述
*/
function getRelativeTime(diffSeconds) {
const diff = Math.abs(diffSeconds);
if (diff < 60) {
return `${Math.ceil(diff)}分钟前`;
} else if (diff < 3600) {
return `${Math.ceil(diff / 60)}小时前`;
} else if (diff < 86400) {
return `${Math.ceil(diff / 3600)}天前`;
} else {
return `${Math.ceil(diff / 86400)}天前`;
}
}
// 使用示例
console.log(getRelativeTime(30)); // "1分钟前"
console.log(getRelativeTime(1800)); // "30小时前"
console.log(getRelativeTime(7200)); // "2天前"
注意事项
1. 精度问题
JavaScript 使用 IEEE 754 双精度浮点数,某些计算可能出现精度误差:
javascript
0.1 + 0.2 === 0.3; // false(实际上是 0.30000000000000004)
// 解决方案:使用 toFixed() 或比较差值
Math.abs(0.1 + 0.2 - 0.3) < Number.EPSILON; // true
(0.1 + 0.2).toFixed(1) === "0.3"; // true
2. NaN 和 Infinity
javascript
Math.sqrt(-1); // NaN
Math.log(0); // -Infinity
1 / 0; // Infinity
parseInt("abc"); // NaN
// 检查是否为有效数字
Number.isNaN(NaN); // true
Number.isFinite(Infinity); // false
Number.isFinite(100); // true
3. 性能考虑
对于频繁调用的数学运算,可以考虑缓存结果或使用位运算优化:
javascript
// 向下取整的替代方案(仅适用于正数)
Math.floor(4.9); // 4
4.9 | 0; // 4(位运算更快)
// 但要注意:位运算会将数字转换为 32 位整数
Math.floor(4294967296.9); // 4294967296
4294967296.9 | 0; // 0(溢出)
4. Math 方法不是构造函数
javascript
// ❌ 错误
const m = new Math();
m.random();
// ✅ 正确
Math.random();
总结
Math 对象是前端开发中处理数值计算的得力助手。掌握以下核心要点:
📌 核心方法速查表
| 方法 | 用途 | 示例 |
|---|---|---|
Math.ceil() |
向上取整 | Math.ceil(4.1) → 5 |
Math.floor() |
向下取整 | Math.floor(4.9) → 4 |
Math.round() |
四舍五入 | Math.round(4.5) → 5 |
Math.max() |
最大值 | Math.max(1, 5, 3) → 5 |
Math.min() |
最小值 | Math.min(1, 5, 3) → 1 |
Math.random() |
随机数 | Math.random() → 0-1 |
Math.abs() |
绝对值 | Math.abs(-5) → 5 |
Math.pow() |
幂运算 | Math.pow(2, 3) → 8 |
Math.sqrt() |
平方根 | Math.sqrt(9) → 3 |
💡 最佳实践
- 文件分片 :用
Math.ceil()计算分片数,用Math.min()限制边界 - 时间转换 :用
Math.floor()提取整数部分,用%取余数 - 数值限制 :组合使用
Math.max()和Math.min()实现 clamp 功能 - 随机数生成 :
Math.floor(Math.random() * (max - min + 1)) + min - 注意精度 :浮点数运算时使用
Number.EPSILON进行比较
🚀 进阶建议
- 熟悉 ES6+ 的新特性,如指数运算符
** - 了解
Number对象的静态方法(Number.isInteger()、Number.isSafeInteger()等) - 对于高精度计算,考虑使用专门的库(如 decimal.js、big.js)
- 在性能敏感的场景中,合理使用位运算优化