如何自己造一个时间处理库

之前我在文章中说自己写时间处理库,有网友问:为什么要自己造一个轮子?是不知道市面上有成熟的库吗?有什么优势吗?

其实我没想那么多,就是把"造一个自己的库"当作一个"课题"或者"挑战"。想要做一个自己用着趁手的工具,并不是别人的不好用,而是想要一个符合自己使用习惯的工具。市面上的库无论方法命名还是使用的逻辑,并不一定符合自己的直觉,而且在开发过程,也能梳理自己的思路。

言归正传,谈谈我对这个库的规划。首先它需要有以下常见功能:

  1. 不同时间数据格式的识别:时间字符串、数组、对象、Date对象、时间戳、ZonedDateTime对象等等;
  2. 对时间进行加减单位、大小对比、不同单位取值,方法支持链式调用;
  3. 不同时间数据格式输出;
  4. 时区和语言全局切换和实例单独切换;
  5. 各种功能之间隔离管理,并且具有扩展性,用户可以自行扩展功能;

调用方式实现

期待的使用方式是像jQuery一样可以实现无new实例化和链式调用

javascript 复制代码
datex(2022,10,1).change('year',1).format()

实现方式我直接仿照jQuery的写法

javascript 复制代码
import prototype from './prototype.js';

// 构造器
function datex(...argu){
    return new datex.prototype.init(...argu);
}

// 无new实例化 - 类似于jQuery
datex.prototype = prototype;
prototype.init.prototype = prototype;

原型设计

实例的方法全部继承于原型,原型的设计直接决定datex().xxx后的方法

javascript 复制代码
export default {
    _date:null,
    parse:function(...argu){
    
        // 解析代码
        this._date = xxx;
        
        return this;
    },
    init:function(...argu){
        this.parse(...argu);

        // 初始化
        let _ = this;
        taskQueue.forEach(function(task){
            task.bind(_)(...argu);
        });
        return this;
    },
    onInit(callback){
        taskQueue.push(callback);
    }
};

数据解析

parse用于解析不同数据格式输入,解析后转换成标准的date对象,_date属性记录每一个实例对象的当前时间。可以把它当作一个时间的"信标",后续所有计算本质是对这个date对象的处理。这也是为什么我将这个库取名为"datex"的原因,我是对它进行扩展重构。

支持链式调用的实例方法都返回当前实例对象this,让方法可以延续;

实例初始化

init为原型初始化方法,taskQueue是内部预留的初始化事件处理队列,用于不同扩展修改初始化方法时使用。后续扩展如何想要在初始化时,扩展解析含蓄,可以在onInit中加入处理逻辑

javascript 复制代码
proto.onInit(function(...argu){
    // 重写方法,可以对实例进行补充
});

目录设计

text 复制代码
/module     - 功能模块
    /method
        /config          - 配置
            period.js    - 时间间隔配置
        /data            - 数据
            timezone     - 时区列表
        /locale          - 语言包
            en-US.json   - 英语
            zh-CN.json   - 简体中文
            zh-HK.json   - 繁体中文
        /runtime         - 运行环境兼容
            globalThis.js
            structuredClone.js
        /utils           - 工具方法
            type.js      - 类型判断
        base.js          - 基础方法
        compare.js       - 时间对比方法
        compute.js       - 时间计算方法
        duration.js      - 时间间隔
        language.js      - 多语言处理
        parse.js         - 解析器扩展
        temporal.js      - 对Temporal的兼容处理
        timezone.js      - 时区支持
    factory.js     - 工厂函数
    prototype.js   - 原型对象
datex.js   - 入口文件

功能模块设计

模块加载

功能模块不是直接写在原型里的,而是按功能模块次序加载。其中datex.extend是原型暴露的扩展方法,可以用于第三方扩展使用,这里内部功能引用也通过它扩展。

javascript 复制代码
import datex from './module/factory.js';
import baseLoader from './module/method/base.js';
import computeLoader from './module/method/compute.js';
import compareLoader from './module/method/compare.js';
import durationLoader from './module/method/duration.js';
import languageLoader from './module/method/language.js';
import timezoneLoader from './module/method/timezone.js';
import temporalLoader from './module/method/temporal.js';
import parseLoader from './module/method/parse.js';

// 功能加载
[
    baseLoader,
    computeLoader,
    compareLoader,
    durationLoader,
    languageLoader,
    timezoneLoader,
    temporalLoader,
    parseLoader,
].forEach(datex.extend);

export default datex;

模块设计

模块仅暴露一个唯一方法function(datex,proto){},就是一个加载器。

datex就是构造器,对它进行方法扩展就是静态方法的实现。如datex.xxx这样的调用。

proto就是原型,对它进行方法扩展就是实例方法的实现。如datex().xxx这样的调用。

proto.onInit是在实例化阶段,对初始化方法重写处理。

javascript 复制代码
 export default function(datex,proto){
    Object.assign(datex,{
        getTimezoneOffset(){

        }
    });

    Object.assign(proto,{
        _timezone:null,
        _offset:0,
        getTimezoneOffset(){

        }
    });

    proto.onInit(function(...argu){

    });

    // 重写
    let set = proto.set;
    let toObject = proto.toObject;
    Object.assign(proto,{
        toObject(){
            let that = this.clone();
            const temp = toObject.bind(that)();

            return temp;
        },
        set(unit,value){

        }
    });
};

方法重写

对象可以通过Object.assign进行扩展或者覆盖,但是扩展并不是将原有的方法直接放弃掉,我们需要先另名保存一份,在新方法最前面调用即可,如上面的const temp = toObject.bind(that)();就是将原有方法绑定进新环境内。

总结

以上说的都是时间处理库实现的大体架构,具体实现其实就是对datexproto两个对象进行方法的编写。核心是对实例中的_date进行计算。

【时间处理库仓库】 github.com/mumuy/datex...

【时间处理库文档】 passer-by.com/datex/

基于本项目实现的世界时间网站

【几点了】 jidianle.com/

【几点钟】 jidianzhong.com/

相关推荐
走到天涯海角2 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!2 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰2 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
mayaairi4 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen4 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能
风骏时光牛马5 小时前
AI源码分析:拆解模型底层实现逻辑
前端
BillKu5 小时前
全局样式变量:CSS 自定义属性(--border-color)和SCSS 变量($border-color)的说明
javascript·css·scss
IT_陈寒5 小时前
React子组件莫名其妙重渲染?你可能漏了这个Hook
前端·人工智能·后端
乘风gg6 小时前
DeepSeek V4.1 Flash 来了,明天中午 Flash 降价 60%
前端·ai编程·claude