Appearance
Day.js 源代码导览
文件结构
Day.js 的源代码结构清晰,易于理解和扩展。
dayjs/
├── index.js # 主入口
├── constant.js # 常量定义
├── utils.js # 工具函数
├── plugin.js # 插件系统
├── dayjs.js # Day.js 类
├── parse.js # 日期解析
├── format.js # 日期格式化
├── get-set.js # 获取和设置
└── locale/ # 国际化核心文件
1. index.js - 主入口
主入口文件,导出 dayjs 函数和 Dayjs 类。
javascript
import dayjs from './dayjs'
import isDayjs from './plugin/isDayjs'
export default dayjs
export { dayjs, isDayjs }2. dayjs.js - Day.js 类
Day.js 类是核心类,封装了日期对象和操作方法。
javascript
import Utils from './utils'
class Dayjs {
constructor(config) {
this.$L = this.$L || config.locale || null
this.$d = config.date
this.init(config)
}
init(config) {
this.$y = this.$d.getFullYear()
this.$M = this.$d.getMonth()
this.$D = this.$d.getDate()
this.$W = this.$d.getDay()
this.$H = this.$d.getHours()
this.$m = this.$d.getMinutes()
this.$s = this.$d.getSeconds()
this.$ms = this.$d.getMilliseconds()
}
// ... 其他方法
}
export default (date, c) => {
c = c || {}
const arg = c.date
const locale = c.locale
const d = arg === undefined
? new Date()
: arg instanceof Date
? arg
: typeof arg === 'string'
? arg.match(/^[0-9]*$/) ? new Date(+arg) : new Date(arg)
: new Date(arg)
return new Dayjs({ date: d, locale })
}关键函数
1. parse() - 解析日期
解析日期字符串:
javascript
function parseDate(config) {
if (config === null || config === undefined) {
return new Date()
}
if (config instanceof Date) {
return config
}
if (typeof config === 'string') {
return new Date(config)
}
if (typeof config === 'number') {
return new Date(config)
}
return new Date()
}2. format() - 格式化日期
格式化日期输出:
javascript
function format(date, formatString) {
const tokens = {
YYYY: date.getFullYear(),
YY: String(date.getFullYear()).slice(-2),
M: date.getMonth() + 1,
MM: padZero(date.getMonth() + 1),
D: date.getDate(),
DD: padZero(date.getDate()),
H: date.getHours(),
HH: padZero(date.getHours()),
m: date.getMinutes(),
mm: padZero(date.getMinutes()),
s: date.getSeconds(),
ss: padZero(date.getSeconds())
}
return formatString.replace(/YYYY|YY|M|MM|D|DD|H|HH|m|mm|s|ss/g, (match) => {
return tokens[match]
})
}3. add() - 添加时间
添加时间到日期:
javascript
function add(date, amount, unit) {
const result = new Date(date)
switch (unit) {
case 'year':
case 'years':
result.setFullYear(result.getFullYear() + amount)
break
case 'month':
case 'months':
result.setMonth(result.getMonth() + amount)
break
case 'day':
case 'days':
result.setDate(result.getDate() + amount)
break
case 'hour':
case 'hours':
result.setHours(result.getHours() + amount)
break
case 'minute':
case 'minutes':
result.setMinutes(result.getMinutes() + amount)
break
case 'second':
case 'seconds':
result.setSeconds(result.getSeconds() + amount)
break
}
return result
}4. subtract() - 减去时间
减去时间:
javascript
function subtract(date, amount, unit) {
return add(date, -amount, unit)
}设计模式
1. 工厂模式
使用工厂模式创建 Day.js 实例:
javascript
export default (date, c) => {
c = c || {}
const arg = c.date
const locale = c.locale
const d = arg === undefined
? new Date()
: arg instanceof Date
? arg
: typeof arg === 'string'
? arg.match(/^[0-9]*$/) ? new Date(+arg) : new Date(arg)
: new Date(arg)
return new Dayjs({ date: d, locale })
}2. 链式调用模式
所有操作返回新的 Day.js 实例,支持链式调用:
javascript
Dayjs.prototype.add = function(number, units) {
const date = new Date(this.$d)
date.setTime(date.getTime() + number * Utils.getUnits(units))
return new Dayjs(date)
}3. 插件模式
使用插件模式扩展功能:
javascript
const installedPlugins = []
function extend(plugin, option) {
if (!plugin.$i) {
plugin(option, Dayjs, dayjs)
plugin.$i = true
installedPlugins.push(plugin)
}
return dayjs
}工具函数
1. padZero() - 补零
补零函数:
javascript
function padZero(num) {
return num < 10 ? `0${num}` : num
}2. isLeapYear() - 判断闰年
判断闰年:
javascript
function isLeapYear(year) {
return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0
}3. getDaysInMonth() - 获取月份天数
获取月份天数:
javascript
function getDaysInMonth(year, month) {
return new Date(year, month + 1, 0).getDate()
}插件实现
1. 插件接口
插件需要实现特定的接口:
javascript
function plugin(option, Dayjs, dayjsClass) {
// 扩展 Dayjs 类
Dayjs.prototype.methodName = function() {
// 实现逻辑
}
// 扩展 dayjs 函数
dayjsClass.staticMethod = function() {
// 实现逻辑
}
}2. 示例插件
示例插件实现:
javascript
export default (option, Dayjs, dayjsClass) => {
dayjsClass.isDayjs = function isDayjs(d) {
return d instanceof Dayjs
}
Dayjs.prototype.isDayjs = function isDayjs() {
return true
}
}国际化
1. 语言包结构
语言包结构:
javascript
export default {
name: 'zh-cn',
weekdays: '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'),
months: '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'),
ordinal: (number) => `${number}日`,
formats: {
LT: 'HH:mm',
LTS: 'HH:mm:ss',
L: 'YYYY/MM/DD',
LL: 'YYYY年M月D日',
LLL: 'YYYY年M月D日 HH:mm',
LLLL: 'YYYY年M月D日dddd HH:mm'
}
}2. 使用语言包
使用语言包:
javascript
import 'dayjs/locale/zh-cn'
dayjs.locale('zh-cn')
dayjs().format('dddd') // '星期一'性能优化
1. 缓存机制
缓存解析和格式化结果:
javascript
const cache = new Map()
function format(date, formatString) {
const key = `${date.getTime()}-${formatString}`
if (cache.has(key)) {
return cache.get(key)
}
const result = formatInternal(date, formatString)
cache.set(key, result)
return result
}2. 惰性计算
惰性计算日期属性:
javascript
class Dayjs {
constructor(config) {
this.$d = config.date
this.$y = null
this.$M = null
this.$D = null
}
get year() {
if (this.$y === null) {
this.$y = this.$d.getFullYear()
}
return this.$y
}
}总结
Day.js 的源代码结构清晰,易于理解和扩展。它采用了模块化设计,核心库轻量,通过插件系统扩展功能。通过本节的学习,你将理解 Day.js 的源代码结构,为后续的核心功能实现打下基础。
