JavaScript 时间格式化的最优方案:从踩坑到优化的终极指南
在代码 review 过程中,我们经常会遇到时间格式化的问题。一个高效、灵活、可维护的 formatDate 方法至关重要。本文将带你从基础实现到优化改进,最终打造最优版本,同时也会深入解析 substr、substring 和 slice 的区别及最佳用法。
一、时间格式化的优化过程
第一版:基础实现
第一版使用 RegExp 处理格式化逻辑,代码结构较为直观,但存在 substr 过时、正则匹配效率优化空间等问题。
public static formatDate(date: Date, fmt: string) {
const o: { [name: string]: number } = {
"M+": date.getMonth() + 1, // 月份
"d+": date.getDate(), // 日
"h+": date.getHours(), // 小时
"m+": date.getMinutes(), // 分
"s+": date.getSeconds(), // 秒
"q+": Math.floor((date.getMonth() + 3) / 3), // 季度
S: date.getMilliseconds(), // 毫秒
};
if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
for (const k in o)
if (new RegExp("(" + k + ")").test(fmt))
fmt = fmt.replace(RegExp.$1, RegExp.$1.length === 1 ? `${o[k]}` : `00${o[k]}`.substr(("" + o[k]).length));
return fmt;
}
缺陷分析:
substr已被废弃,应使用slice或substring代替。- 正则表达式直接操作
RegExp.$1可能不稳定,推荐使用match回调替换。 - 格式化补零逻辑不够优雅,可以优化字符串处理方式。
第二版:优化代码结构
第二版采用 substring 代替 substr,并提升 RegExp 处理方式,使代码更清晰。
public static formatDate(format: string, date = new Date()) {
const o = {
'M+': date.getMonth() + 1, // 月份
'D+': date.getDate(), // 日
'h+': date.getHours(), // 时
'm+': date.getMinutes(), // 分
's+': date.getSeconds(), // 秒
'q+': Math.floor((date.getMonth() + 3) / 3), // 季度
S: date.getMilliseconds(), // 毫秒
}
// 处理年份
if (/Y+/.test(format)) {
format = format.replace(/Y+/, match => (date.getFullYear() + '').substring(4 - match.length))
}
// 处理其他格式
for (const [k, v] of Object.entries(o)) {
const sv = v.toString()
const reg = new RegExp(`(${k})`)
if (reg.test(format)) {
format = format.replace(reg, match => (match.length === 1 ? sv : `00${sv}`.substring(sv.length)))
}
}
return format
}
优化点:
substr替换为substring,提高兼容性。- 使用
match回调替换字符串,避免直接操作RegExp.$1。 Object.entries(o)方式遍历o,让代码更现代化。
最终版:终极优化
最终版采用 slice 进一步简化字符串操作,提高可读性和执行效率。
public static formatDate(date: Date, fmt: string): string {
const o: { [key: string]: number } = {
"M+": date.getMonth() + 1, // 月份
"d+": date.getDate(), // 日
"h+": date.getHours(), // 小时
"m+": date.getMinutes(), // 分钟
"s+": date.getSeconds(), // 秒
"q+": Math.floor((date.getMonth() + 3) / 3), // 季度
S: date.getMilliseconds(), // 毫秒
};
// 处理年份
if (/y+/.test(fmt)) {
fmt = fmt.replace(/y+/, (match) => date.getFullYear().toString().slice(-match.length));
}
// 处理其他格式
for (const k in o) {
const regex = new RegExp(`(${k})`);
if (regex.test(fmt)) {
fmt = fmt.replace(regex, (match) => (match.length === 1 ? `${o[k]}` : `00${o[k]}`.slice(-match.length)));
}
}
return fmt;
}
最终优化点:
substring改为slice,让代码更简洁高效。- 使用
slice(-match.length)直接获取年份的后 N 位,避免复杂计算。 - 补零逻辑优化:使用
slice(-match.length)替代substring,使代码更直观。
二、substr、substring 和 slice 的正确用法
在时间格式化过程中,我们用到了 substr、substring 和 slice,它们的区别如下:
| 方法 | 语法 | 作用 | 关键区别 |
|---|---|---|---|
substr |
str.substr(start, length) |
从 start 位置开始,截取 length 长度的字符串 |
已废弃,不建议使用 |
substring |
str.substring(start, end) |
截取 start 到 end(不包括 end)的部分 |
start > end 时会自动交换参数 |
slice |
str.slice(start, end) |
截取 start 到 end(不包括 end)的部分 |
支持负数索引,更推荐使用 |
最佳实践:
slice是最推荐的,尤其在处理负数索引时更灵活。substring适用于简单截取,但不能处理负数索引。- 避免使用
substr,因为它已被废弃,未来可能被移除。
示例代码:
const str = "JavaScript";
// substring: 取 "Java"
console.log(str.substring(0, 4));
// slice: 取 "Script"
console.log(str.slice(-6));
// substr(不推荐): 取 "Java"
console.log(str.substr(0, 4));
总结
- 时间格式化方法的优化
- 第一版:基础实现,但使用了过时方法。
- 第二版:优化代码结构,使用
substring,提高可读性。 - 最终版:采用
slice,代码更简洁高效。
substr、substring和slice的正确用法- 推荐使用
slice,避免substr。
- 推荐使用
通过这次优化,我们得到了一个高效、现代、易维护的 formatDate 方法。希望这篇文章能帮助你在实际项目中写出更优雅的代码!🚀