Day.js 源码深度剖析:极简时间库的设计艺术
1. 项目背景与构建流程
Day.js (v1.11.20) 是一个轻量级的 JavaScript 时间处理库,其 API 设计高度兼容 Moment.js。 通过分析 package.json 可知,该项目使用 Rollup 作为构建工具,通过"编译、打包、压缩"三部曲生成最终的 dayjs.min.js,而这一切的核心入口正是 src/index.js。
2 多级缓存策略
Day.js 通过两级缓存机制实现高效的日期操作和格式化。
2.1全局 Locale 缓存
Ls 对象用于缓存已加载的语言包,避免重复加载和解析:
javascript
let L = 'en' // global locale
const Ls = {} // global loaded locale
const parseLocale = (preset, object, isLocal) => {
let l
if (!preset) return L
if (typeof preset === 'string') {
const presetLower = preset.toLowerCase()
if (Ls[presetLower]) {
l = presetLower
}
if (object) {
Ls[presetLower] = object
l = presetLower
}
const presetSplit = preset.split('-')
if (!l && presetSplit.length > 1) {
return parseLocale(presetSplit[0])
}
} else {
const { name } = preset
Ls[name] = preset
l = name
}
if (!isLocal && l) L = l
return l || (!isLocal && L)
}
2.2数据缓存与初始化
Day.js 在实例化时会调用 init() 方法,将日期对象的各项数值解构并缓存到实例属性中,从而实现高效的格式化输出。
javascript
init() {
const { $d } = this
this.$y = $d.getFullYear()
this.$M = $d.getMonth()
this.$D = $d.getDate()
this.$W = $d.getDay()
this.$H = $d.getHours()
this.$m = $d.getMinutes()
this.$s = $d.getSeconds()
this.$ms = $d.getMilliseconds()
}
3. 灵活的插件系统
Day.js 的核心非常精简,复杂功能主要通过 extend 静态方法注入。
3.1 dayjs.extend 实现原理
插件接受三个参数:配置选项 option、类引用 Dayjs 和工厂函数 dayjs。
javascript
dayjs.extend = (plugin, option) => {
if (!plugin.$i) { // 确保插件只安装一次
plugin(option, Dayjs, dayjs)
plugin.$i = true
}
return dayjs
}
3.2 插件开发示例:isToday
我们可以通过扩展 Dayjs.prototype 轻松实现自定义功能:
javascript
const myPlugin = (o, c, d) => {
const proto = c.prototype
proto.isToday = function () {
const comparisonTemplate = 'YYYY-MM-DD'
const now = d()
return this.format(comparisonTemplate) === now.format(comparisonTemplate)
}
}
// 使用插件
dayjs.extend(myPlugin)
dayjs().isToday() // true/false
dayjs('2024-03-20').isToday()
3.3内置插件使用
javascript
import advancedFormat from 'dayjs/plugin/advancedFormat' // load on demand
dayjs.extend(advancedFormat) // use plugin
dayjs().format('Q Do k kk X x') // more available formats
4. 国际化 (i18n) 设计
Day.js 提供了极其详尽的本地化配置,支持日期格式化模版、相对时间描述及复杂的时间段判断。
javascript
const locale = {
name: 'zh-cn',
weekdays: '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'),
months: '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'),
// ... 其他配置
meridiem: (hour, minute) => {
const hm = (hour * 100) + minute
if (hm < 600) return '凌晨'
else if (hm < 900) return '早上'
else if (hm < 1100) return '上午'
else if (hm < 1300) return '中午'
else if (hm < 1800) return '下午'
return '晚上'
}
}
5. 总结
Day.js 通过严谨的依赖管理、高效的属性缓存以及极具扩展性的插件系统,完美平衡了"轻量级"与"功能性"。它是现代前端开发中处理时间数据的首选库之一。