文章目录
- 需求分析
- 具体实现
- 完整源码
不知道大家有没有尝试封装过一个时间格式化的函数啊,在之前我封装的时候,开始是觉得手到擒来,但是实践之后发现写非常的shi啊,大量的分支判断,哪怕是映射起到的作用也只是稍微好一点,不过比较好的是,当天晚上我就看见了袁教头的参数归一化讲解啊,立马就让我眼界大开,如果你也不知道,就一起来看一下
需求分析
-
时间格式化,一个基础的知识,也没有什么难度,但是如果要变得通用一点,那么就不是那么容易处理了
-
由这个参数最为难搞,比如存在一个 formatDateTime 方法,使用如下:
// 日期 2023-12-29 formatDateTime(new Date(), 'date')// 日期时间 2023-12-29 6:23:3 formatDateTime(new Date(), 'dateTime')// 年月日时分秒[不补0] 2023-12-29 6:23:3 formatDateTime(new Date(), 'yyyy-MM-dd HH:mm:ss')// 年月日时分秒 2023-12-29 06:23:03 formatDateTime(new Date(), 'yyyy-MM-dd HH:mm:ss', true)// 年月日时分秒毫秒 2023-12-29 06:23:03:015 formatDateTime(new Date(), 'yyyy-MM-dd HH:mm:ss:ms', true)// 自定义函数处理 formatDateTime(new Date(), dateInfo => {// ... })
-
那诸如这些情况,怎么写呢,最简单粗暴的就莫过于 if 判断了,但是这种判断写起来的话可想而知
-
所以应该怎么处理呢?其实仔细看一下,这些参数无论是 date 还是 dateTime 或者其他,最后无非就是要得到一个格式化后的时间,那么这一步都是可以通过一个函数来处理完成的,所以我们首先第一步就是搞定,无论参数是什么情况,都将其转化为一个函数,而这种将不同的情况转换为一种情况,就是参数归一化
具体实现
-
我们上面列举的参数大致可以分为传递的函数和字符串,字符串又分为固定的词汇和用户传入一些自定义的时间格式,但是 yyyy-MM-dd HH:mm:ss 这种情况是可以将 date、dateTime 也包含在内的,所以如果我们可以将这个 date 转为 yyyy-MM-dd,将 dateTime 转为 yyyy-MM-dd HH:mm:ss 是不是就可以将多种情况变为一种情况了
-
要完成这个参数的归一,我们需要一个辅助函数,这个函数会返回给我们一个函数,定义函数 _format,如下:
function _format(format) {}function formatDateTime(date, format, isPad) {const f = _format(format) }
-
那么 _format 函数应该怎么实现呢?首先判断类型,传入的参数是否是一个函数,如果是一个函数则直接返回,在判断是否是一个字符串,如果是字符串在将 date 和 dateTime 变为自定义的格式,如下:
function _format(format) {if (typeof format === 'function') {return format}if (typeof format !== 'string') {throw new Error('format must be string or function')}if (format === 'date') {format = 'yyyy-MM-dd'}if (format === 'dateTime') {format = 'yyyy-MM-dd HH:mm:ss'} }
-
此时我们就已经将参数都处理为一种情况了。现在就是返回一个函数来出来这个结果,怎么处理呢?那只能是你给我一些数据,比如 year、month… 等等这些信息,然后我这个返回的函数内部替换一下即可,如下:
function _format(format) {if (typeof format === 'function') {return format}if (typeof format !== 'string') {throw new Error('format must be string or function')}if (format === 'date') {format = 'yyyy-MM-dd'}if (format === 'dateTime') {format = 'yyyy-MM-dd HH:mm:ss'}const result = dateInfo => {const { year, month, day, hour, minute, second, millisecond } = dateInforeturn format.replaceAll('yyyy', year).replaceAll('MM', month).replaceAll('dd', day).replaceAll('HH', hour).replaceAll('mm', minute).replaceAll('ss', second).replaceAll('ms', millisecond)}return result }
-
可以看到,我们需要返回的这个函数,需要接收一些数据,那这些是不是就很好处理了呢,如下:
function isDate(value) {return value instanceof Date }function formatDateTime(date, format, isPad) {// 判断传递的 date 是否是一个时间对象date = isDate(date) ? date : new Date(date)// 如果 date 为 Invalid Date 就报错if (isNaN(date.getTime())) {throw new Error('Invalid Date')}const f = _format(format)// 得到 year, month, day, hour, minute, second, millisecondconst dateInfo = {year: date.getFullYear().toString(),month: (date.getMonth() + 1).toString(),day: date.getDate().toString(),hour: date.getHours().toString(),minute: date.getMinutes().toString(),second: date.getSeconds().toString(),millisecond: date.getMilliseconds().toString()} }
-
此时我们还需要对这些数据进行进一步的处理,比如是否补零,如下:
function formatDateTime(date, format, isPad) {// 判断传递的 date 是否是一个时间对象date = isDate(date) ? date : new Date(date)// 如果 date 为 Invalid Date 就报错if (isNaN(date.getTime())) {throw new Error('Invalid Date')}const f = _format(format)// 得到 year, month, day, hour, minute, second, millisecondconst dateInfo = {year: date.getFullYear().toString(),month: (date.getMonth() + 1).toString(),day: date.getDate().toString(),hour: date.getHours().toString(),minute: date.getMinutes().toString(),second: date.getSeconds().toString(),millisecond: date.getMilliseconds().toString()}function _isPad(prop, len) {dateInfo[prop] = dateInfo[prop].padStart(len, '0')}// 是否补零if (isPad) {_isPad('year', 4)_isPad('month', 2)_isPad('day', 2)_isPad('hour', 2)_isPad('minute', 2)_isPad('second', 2)_isPad('millisecond', 3)}return f(dateInfo) }
-
结果如图:
-
来看看传递函数的结果,如图:
-
基于此,我们还可以更换分割符使用,如下:
-
怎么样,这样是不是对比直接使用 if 来判断参数格式化,要优雅不少呢
完整源码
function _format(format) {if (typeof format === 'function') {return format}if (typeof format !== 'string') {throw new Error('format must be string or function')}if (format === 'date') {format = 'yyyy-MM-dd'}if (format === 'dateTime') {format = 'yyyy-MM-dd HH:mm:ss'}const result = dateInfo => {const { year, month, day, hour, minute, second, millisecond } = dateInforeturn format.replaceAll('yyyy', year).replaceAll('MM', month).replaceAll('dd', day).replaceAll('HH', hour).replaceAll('mm', minute).replaceAll('ss', second).replaceAll('ms', millisecond)}return result
}function isDate(value) {return value instanceof Date
}function formatDateTime(date, format, isPad) {date = isDate(date) ? date : new Date(date)if (isNaN(date.getTime())) {throw new Error('Invalid Date')}const f = _format(format)const dateInfo = {year: date.getFullYear().toString(),month: (date.getMonth() + 1).toString(),day: date.getDate().toString(),hour: date.getHours().toString(),minute: date.getMinutes().toString(),second: date.getSeconds().toString(),millisecond: date.getMilliseconds().toString()}function _isPad(prop, len) {dateInfo[prop] = dateInfo[prop].padStart(len, '0')}if (isPad) {_isPad('year', 4)_isPad('month', 2)_isPad('day', 2)_isPad('hour', 2)_isPad('minute', 2)_isPad('second', 2)_isPad('millisecond', 3)}return f(dateInfo)
}