摘要:前言上一篇源碼解析三構造函數介紹了的源碼中的函數。接下來,本篇將解讀一下中的類。首先,我們看的構造函數,該構造函數調用了實例方法,傳入參數在上一篇有講到。下一篇源碼解析五插件詳解
前言
上一篇 dayjs 源碼解析(三)(dayjs 構造函數)介紹了 dayjs 的源碼中的 dayjs 函數。接下來,本篇將解讀一下 index.js 中的 Dayjs 類。
class Dayjs { constructor(cfg) { this.parse(cfg) // for plugin } parse(cfg) { this.$d = parseDate(cfg.date) this.init(cfg) } init(cfg) { this.$y = this.$d.getFullYear() // 年 this.$M = this.$d.getMonth() // 月(注意從 0 開始) this.$D = this.$d.getDate() // 日 this.$W = this.$d.getDay() // 周幾(0 表示周日) this.$H = this.$d.getHours() // 時 this.$m = this.$d.getMinutes() // 分 this.$s = this.$d.getSeconds() // 秒 this.$ms = this.$d.getMilliseconds() // 毫秒 this.$L = this.$L || parseLocale(cfg.locale, null, true) || L // 語言,默認為 "en" } // 下面的都是實例方法 $utils() { return Utils } isValid() { return !(this.$d.toString() === "Invalid Date") } isLeapYear() { return ((this.$y % 4 === 0) && (this.$y % 100 !== 0)) || (this.$y % 400 === 0) } $compare(that) { return this.valueOf() - dayjs(that).valueOf() } isSame(that) { return this.$compare(that) === 0 } isBefore(that) { return this.$compare(that) < 0 } isAfter(that) { return this.$compare(that) > 0 } year() { return this.$y } month() { return this.$M } day() { return this.$W } date() { return this.$D } hour() { return this.$H } minute() { return this.$m } second() { return this.$s } millisecond() { return this.$ms } unix() { return Math.floor(this.valueOf() / 1000) } valueOf() { // timezone(hour) * 60 * 60 * 1000 => ms return this.$d.getTime() } startOf(units, startOf) { // startOf -> endOf const isStartOf = !Utils.isUndefined(startOf) ? startOf : true const unit = Utils.prettyUnit(units) const instanceFactory = (d, m) => { const ins = wrapper(new Date(this.$y, m, d), this) return isStartOf ? ins : ins.endOf(C.D) } const instanceFactorySet = (method, slice) => { const argumentStart = [0, 0, 0, 0] const argumentEnd = [23, 59, 59, 999] return wrapper(this.toDate()[method].apply( // eslint-disable-line prefer-spread this.toDate(), isStartOf ? argumentStart.slice(slice) : argumentEnd.slice(slice) ), this) } switch (unit) { case C.Y: return isStartOf ? instanceFactory(1, 0) : instanceFactory(31, 11) case C.M: return isStartOf ? instanceFactory(1, this.$M) : instanceFactory(0, this.$M + 1) case C.W: return isStartOf ? instanceFactory(this.$D - this.$W, this.$M) : instanceFactory(this.$D + (6 - this.$W), this.$M) case C.D: case C.DATE: return instanceFactorySet("setHours", 0) case C.H: return instanceFactorySet("setMinutes", 1) case C.MIN: return instanceFactorySet("setSeconds", 2) case C.S: return instanceFactorySet("setMilliseconds", 3) default: return this.clone() } } endOf(arg) { return this.startOf(arg, false) } $set(units, int) { // private set const unit = Utils.prettyUnit(units) switch (unit) { case C.DATE: this.$d.setDate(int) break case C.M: this.$d.setMonth(int) break case C.Y: this.$d.setFullYear(int) break case C.H: this.$d.setHours(int) break case C.MIN: this.$d.setMinutes(int) break case C.S: this.$d.setSeconds(int) break case C.MS: this.$d.setMilliseconds(int) break default: break } this.init() return this } set(string, int) { return this.clone().$set(string, int) } add(number, units) { number = Number(number) // eslint-disable-line no-param-reassign const unit = Utils.prettyUnit(units) const instanceFactory = (u, n) => { const date = this.set(C.DATE, 1).set(u, n + number) return date.set(C.DATE, Math.min(this.$D, date.daysInMonth())) } if (unit === C.M) { return instanceFactory(C.M, this.$M) } if (unit === C.Y) { return instanceFactory(C.Y, this.$y) } let step switch (unit) { case C.MIN: step = C.MILLISECONDS_A_MINUTE break case C.H: step = C.MILLISECONDS_A_HOUR break case C.D: step = C.MILLISECONDS_A_DAY break case C.W: step = C.MILLISECONDS_A_WEEK break case C.S: step = C.MILLISECONDS_A_SECOND break default: // ms step = 1 } const nextTimeStamp = this.valueOf() + (number * step) return wrapper(nextTimeStamp, this) } subtract(number, string) { return this.add(number * -1, string) } format(formatStr) { const str = formatStr || C.FORMAT_DEFAULT const zoneStr = Utils.padZoneStr(this.$d.getTimezoneOffset()) const locale = this.$locale() const { weekdays, months } = locale const getShort = (arr, index, full, length) => ( (arr && arr[index]) || full[index].substr(0, length) ) return str.replace(C.REGEX_FORMAT, (match) => { if (match.indexOf("[") > -1) return match.replace(/[|]/g, "") switch (match) { case "YY": return String(this.$y).slice(-2) case "YYYY": return String(this.$y) case "M": return String(this.$M + 1) case "MM": return Utils.padStart(this.$M + 1, 2, "0") case "MMM": return getShort(locale.monthsShort, this.$M, months, 3) case "MMMM": return months[this.$M] case "D": return String(this.$D) case "DD": return Utils.padStart(this.$D, 2, "0") case "d": return String(this.$W) case "dd": return getShort(locale.weekdaysMin, this.$W, weekdays, 2) case "ffffd": return getShort(locale.weekdaysShort, this.$W, weekdays, 3) case "ffffdd": return weekdays[this.$W] case "H": return String(this.$H) case "HH": return Utils.padStart(this.$H, 2, "0") case "h": case "hh": if (this.$H === 0) return 12 return Utils.padStart(this.$H < 13 ? this.$H : this.$H - 12, match === "hh" ? 2 : 1, "0") case "a": return this.$H < 12 ? "am" : "pm" case "A": return this.$H < 12 ? "AM" : "PM" case "m": return String(this.$m) case "mm": return Utils.padStart(this.$m, 2, "0") case "s": return String(this.$s) case "ss": return Utils.padStart(this.$s, 2, "0") case "SSS": return Utils.padStart(this.$ms, 3, "0") case "Z": return zoneStr default: // "ZZ" return zoneStr.replace(":", "") } }) } diff(input, units, float) { const unit = Utils.prettyUnit(units) const that = dayjs(input) const diff = this - that let result = Utils.monthDiff(this, that) switch (unit) { case C.Y: result /= 12 break case C.M: break case C.Q: result /= 3 break case C.W: result = diff / C.MILLISECONDS_A_WEEK break case C.D: result = diff / C.MILLISECONDS_A_DAY break case C.H: result = diff / C.MILLISECONDS_A_HOUR break case C.MIN: result = diff / C.MILLISECONDS_A_MINUTE break case C.S: result = diff / C.MILLISECONDS_A_SECOND break default: // milliseconds result = diff } return float ? result : Utils.absFloor(result) } daysInMonth() { return this.endOf(C.M).$D } $locale() { // get locale object return Ls[this.$L] } locale(preset, object) { const that = this.clone() that.$L = parseLocale(preset, object, true) return that } clone() { return wrapper(this.toDate(), this) } toDate() { return new Date(this.$d) } toArray() { return [ this.$y, this.$M, this.$D, this.$H, this.$m, this.$s, this.$ms ] } toJSON() { return this.toISOString() } toISOString() { // ie 8 return // new Dayjs(this.valueOf() + this.$d.getTimezoneOffset() * 60000) // .format("YYYY-MM-DDTHH:mm:ss.SSS[Z]") return this.toDate().toISOString() } toObject() { return { years: this.$y, months: this.$M, date: this.$D, hours: this.$H, minutes: this.$m, seconds: this.$s, milliseconds: this.$ms } } toString() { return this.$d.toUTCString() } }
上面是類 Dayjs 中的所有代碼。
首先,我們看 Dayjs 的構造函數,該構造函數調用了 Dayjs 實例方法 parse ,傳入 cfg 參數(cfg 在 上一篇 有講到)。
在 parse 實例方法中,會使用 parseDate 函數,傳入 cfg.date 屬性,得到 JavaScript 中原生的 Date 對象,且將 Date 對象保存在 Dayjs 實例屬性(實例中的屬性)中。然后再調用實例方法 init 來初始化 Dayjs 實例的其他屬性。
在 init 實例方法中,使用實例屬性 $d(為 JavaScript 原生 Date 對象)來獲取 年、月、日、周幾、時、分、秒、毫秒,且保存在實例中。并且調用 parseLocale 函數來獲取語言,賦值給 Dayjs 實例的 $L 屬性。
再下面的代碼,便是實例方法了,即在 第一篇 所講的 api 都是實例方法,源碼都可以在這里找到。
在 Dayjs 類中 add、subtract 等方法,都會返回一個新的 Dayjs 實例,是通過使用 Dayjs 類中的 clone() 方法實現的。所以,通過這個 clone() 方法,實現了 dayjs 的 immutable 特性。
下一篇:dayjs 源碼解析(五)(dayjs 插件詳解)
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/95984.html
摘要:前言上一篇源碼解析四類介紹了的源碼目錄結構。接下來,本篇將分析一下中插件功能的用法源碼以及如何編寫自己的插件。并且,可以通過插件選項,來對插件進行配置。 前言 上一篇 dayjs 源碼解析(四)(Dayjs 類)介紹了 dayjs 的源碼目錄結構。接下來,本篇將分析一下 dayjs 中插件功能的用法、源碼以及如何編寫自己的 dayjs 插件。 dayjs 插件用法 dayjs 的插件,...
摘要:接下來,本篇將解讀一下中的構造函數。最后將傳入類的構造函數,生成一個對象,作為函數的返回值給返回了。參數通過上面對參數的分析知道了參數其實是當參數為實例對象時,最后又會調用函數,此時才會傳入參數。 前言 上一篇 dayjs 源碼解析(二)(目錄結構)介紹了 dayjs 的源碼目錄結構。接下來,本篇將解讀一下 index.js 中的 dayjs 構造函數。 dayjs 構造函數 // ...
摘要:下面,我將自己閱讀的源碼的過程記錄下來。閱讀庫的代碼,首先先要知道這個庫的作用是一個輕量的時間日期處理庫,其用法和完全一樣。介紹首先,閱讀的源碼,我們應該從的入手。對象是不可變的,即所有改變的操作都會返回一個新的實例。 前言 作為一個程序員,閱讀別人優秀代碼是提升自己技術能力的一個很好的方法。下面,我將自己閱讀 dayjs(v1.6.10)的源碼的過程記錄下來。 閱讀庫的代碼,首先先要...
摘要:前言上一篇源碼解析一,介紹了一下的,知道了如何使用。本篇,介紹項目的目錄結構。源碼解析三構造函數 前言 上一篇 dayjs 源碼解析(一)(api),介紹了一下 dayjs 的 api,知道了如何使用 dayjs。本篇,介紹 dayjs 項目的目錄結構。 目錄結構 showImg(https://segmentfault.com/img/bVbcW0Q?w=229&h=832); 在 ...
showImg(https://segmentfault.com/img/bV9wV7?w=1952&h=712);Moment.js 是一個大而全的 JS 時間庫,很大地方便了我們處理日期和時間。但是 Moment.js太重了(200k+ with locals),可能一般項目也只使用到了她幾個常用的API。雖然社區也有幾個輕量的時間庫,要想遷移過去又會增加新的學習和遷移成本。 如果能有一個和 ...
閱讀 1876·2021-09-28 09:36
閱讀 2426·2021-09-08 09:35
閱讀 3067·2019-08-30 15:53
閱讀 1554·2019-08-30 14:08
閱讀 665·2019-08-29 18:40
閱讀 2843·2019-08-29 13:57
閱讀 2702·2019-08-29 13:55
閱讀 681·2019-08-26 13:45