Moment.js:moment(string,format)源码解析
2021-02-14 02:17
阅读:769
YPE html>
标签:har 轻量级 port token maps fse actor and const
1 概述
- 最近被Safari浏览坑了两次:new Date(‘2020-05-30 15:18:30.254‘) -> Invalid Date;
- 咨询公司里的前端大佬,发现他们前端都用Moment.js做日期转换;
- 为什么Moment.js能够实现任意日期字符串格式转换呢? 先上结论:底层使用new Date(年,月,日,时,分,秒,毫秒)函数,这个函数基本上所有浏览器都实现了。
注:Moment.js很重(源码为4600行左右),所以有很多替代方案的,如:Dayjs、miment等,甚至根据浏览器的兼容情况自行写个轻量级的库也是可行的。
2 使用
Learn MomentJs
3 源码跟踪
- 1 初始化moment():返回createLocal函数;
- 2 初始化配置类:调用createLocal函数 -> createLocalOrUTC函数 ;
- 3 完善配置信息并校验:prepareConfig函数 -> configFromStringAndFormat函数 -> configFromArray函数 -> checkOverflow函数;
- 4 根据配置信息创建Moment对象:Moment构造函数。
;(function (global, factory) {
typeof exports === ‘object‘ && typeof module !== ‘undefined‘ ? module.exports = factory() :
typeof define === ‘function‘ && define.amd ? define(factory) :
global.moment = factory()
}(this, (function () { ‘use strict‘;
var hookCallback;
function hooks () {
return hookCallback.apply(null, arguments);
}
function setHookCallback (callback) {
hookCallback = callback;
}
// 2 初始化配置类
// 2.1 ex: input="2020-05-30 14:08:35",format="YYYY-MM-DD HH:mm:ss",locale=null,strict=null
function createLocal (input, format, locale, strict) {
return createLocalOrUTC(input, format, locale, strict, false);
}
// 2.2 创建Local或者UTC Moment对象
function createLocalOrUTC (input, format, locale, strict, isUTC) {
var c = {};
// 检验input字符串
if ((isObject(input) && isObjectEmpty(input)) ||
(isArray(input) && input.length === 0)) {
input = undefined;
}
// 配置初始化
c._useUTC = c._isUTC = isUTC;
c._l = locale;
c._i = input;
c._f = format;
c._strict = strict;
return createFromConfig(c);
}
// 4 通过配置类创建Moment对象
function createFromConfig (config) {
var res = new Moment(checkOverflow(prepareConfig(config)));
if (res._nextDay) {
res.add(1, ‘d‘);
res._nextDay = undefined;
}
return res;
}
// 3 完善配置信息
function prepareConfig (config) {
var input = config._i,
format = config._f;
config._locale = config._locale || getLocale(config._l);
if (input === null || (format === undefined && input === ‘‘)) {
return createInvalid({nullInput: true});
}
if (typeof input === ‘string‘) {
config._i = input = config._locale.preparse(input);
}
// 支持Moment对象、日期对象、数组对象、字符串格式、配置对象格式
if (isMoment(input)) {
return new Moment(checkOverflow(input));
} else if (isDate(input)) {
config._d = input;
} else if (isArray(format)) {
configFromStringAndArray(config);
} else if (format) {
// 以此为例
configFromStringAndFormat(config);
} else {
configFromInput(config);
}
if (!isValid(config)) {
config._d = null; // _d为日期对象,下面讲解。
}
return config;
}
// 3.1 通过字符串模板创建Moment对象中的日期对象(_d)
function configFromStringAndFormat(config) {
// 创建Date对象用的数组,如:[年,月,日,时,分,秒]
config._a = [];
getParsingFlags(config).empty = true;
var string = ‘‘ + config._i,
i, parsedInput, tokens, token, skipped,
stringLength = string.length,
totalParsedInputLength = 0;
// tokens=[‘YYYY‘,‘-‘,‘MM‘,‘-‘,‘DD‘,‘ ‘,‘HH‘,‘:‘,‘mm‘,‘:‘,‘ss‘]
tokens = expandFormat(config._f, config._locale).match(formattingTokens) || [];
for (i = 0; i 0) {
getParsingFlags(config).unusedInput.push(skipped);
}
string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
totalParsedInputLength += parsedInput.length;
}
if (formatTokenFunctions[token]) {
if (parsedInput) {
getParsingFlags(config).empty = false;
}
else {
getParsingFlags(config).unusedTokens.push(token);
}
// 将parsedInput添加到config._a数组中
addTimeToArrayFromToken(token, parsedInput, config);
}
else if (config._strict && !parsedInput) {
getParsingFlags(config).unusedTokens.push(token);
}
}
// add remaining unparsed input length to the string
getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength;
if (string.length > 0) {
getParsingFlags(config).unusedInput.push(string);
}
// clear _12h flag if hour is 0) {
getParsingFlags(config).bigHour = undefined;
}
getParsingFlags(config).parsedDateParts = config._a.slice(0);
getParsingFlags(config).meridiem = config._meridiem;
// handle meridiem
config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], config._meridiem);
configFromArray(config);
checkOverflow(config);
}
// 3.2 当config._a日期相关数组完善后
function configFromArray (config) {
var i, date, input = [], currentDate, expectedWeekday, yearToUse;
// 年月日
currentDate = currentDateArray(config);
// ...
// 简单描述:将config._a数组中的元素暂存至input数组中用于调用createDate方法。
// Default to current date.
// * if no year, month, day of month are given, default to today
// * if day of month is given, default month and year
// * if month is given, default only year
// * if year is given, don‘t default anything
for (i = 0; i = 0) {
date = new Date(y + 400, m, d, h, M, s, ms);
if (isFinite(date.getFullYear())) {
date.setFullYear(y);
}
} else {
// 最终调用通用的日期创建方法(这个方法所有浏览器都实现了)
date = new Date(y, m, d, h, M, s, ms);
}
return date;
}
// 4 创建Moment对象
function Moment(config) {
copyConfig(this, config);
this._d = new Date(config._d != null ? config._d.getTime() : NaN);
if (!this.isValid()) {
this._d = new Date(NaN);
}
// Prevent infinite loop in case updateOffset creates new moment
// objects.
if (updateInProgress === false) {
updateInProgress = true;
hooks.updateOffset(this);
updateInProgress = false;
}
}
// 中间省略亿点细节
hooks.version = ‘2.24.0‘;
// 设置hooks为createLocal
setHookCallback(createLocal);
// currently HTML5 input type only supports 24-hour formats
hooks.HTML5_FMT = {
DATETIME_LOCAL: ‘YYYY-MM-DDTHH:mm‘, //
DATETIME_LOCAL_SECONDS: ‘YYYY-MM-DDTHH:mm:ss‘, //
DATETIME_LOCAL_MS: ‘YYYY-MM-DDTHH:mm:ss.SSS‘, //
DATE: ‘YYYY-MM-DD‘, //
TIME: ‘HH:mm‘, //
TIME_SECONDS: ‘HH:mm:ss‘, //
TIME_MS: ‘HH:mm:ss.SSS‘, //
WEEK: ‘GGGG-[W]WW‘, //
MONTH: ‘YYYY-MM‘ //
};
// 1. 返回hooks,实际返回createLocal函数
return hooks;
})));
3 参考
ECMAScript? Language Specification
invalid date in safari
Moment.js:moment(string,format)源码解析
标签:har 轻量级 port token maps fse actor and const
原文地址:https://www.cnblogs.com/linzhanfly/p/12993641.html
文章来自:搜素材网的编程语言模块,转载请注明文章出处。
文章标题:Moment.js:moment(string,format)源码解析
文章链接:http://soscw.com/essay/55067.html
文章标题:Moment.js:moment(string,format)源码解析
文章链接:http://soscw.com/essay/55067.html
评论
亲,登录后才可以留言!