年末一直在抽空学习 Chrome 扩展开发以及 Dart 、 Flutter 的移动端开发,两个多月没有更新文章。在这里顺便把 2021 的学习计划更新下。
春节期间已经实现了一个自定义配置的多引擎搜索扩展 Rummage,下一篇分享下扩展的设计、开发和发布,再进一步学习计划如下:
- 学习
TypeScript,抽空开发一个配色应用,名字还没想好,应用应该内置大量经典配色盘,还可以将任意图片量化为一组配色并保存,而且用TypeScript实现Chrome 扩展和用Flutter实现移动端APP两个平台。 源码阅读计划:继续完成lodash的源码分析,学习Vue3和ElementUI的源码实现。地铁读书计划:早晚地铁读《学习 Javascript 数据结构与算法》、《Javascript 设计模式与开发实践》、《Flutter 实战》和重读《Javascript 高级程序设计 3》工具学习计划:Webpack和Git的深入学习。
接上篇 —— dayjs 源码解析(三):插件(中) —— 继续解析 dayjs 的源码。
剩余的插件功能比较零散,实现起来也比较简单,所以解析的代码不全部放在文章里了,简单介绍下剩余每个插件的功能:
advancedFormat:实现更复杂的格式化;arraySupport:实现对数组结构参数的支持;badMutable:由不可变对象转变成可变对象;buddhistEra:实现东南亚佛历的格式化;calendar:实现日历;dayOfYear:返回一个number来表示日期是年中第几天,或设置成是年中第几天;devHelper:开发时插件,显示一些提示和警告方便开发。;localData和localizedFormat:实现本地化(这一块看的有点懵);minMax:挑选最大值或最小值;pluralGetSet:给每个单位添加复数形式方法,与非复数同名函数一致;toArray和toObject:返回时间数组或对象;updateLocale:更新指定语言的任何属性,而其他属性将会保持不变 ;
具体的分析已经放在了 Github 中,感兴趣可以移步对应文件。本篇作为 dayjs 源码解析系列的最后一篇,来动手实现一个自己的插件。
目录如下:
- dayjs 源码解析(一):概念、locale、constant、utils
- dayjs 源码解析(二):Dayjs 类
- dayjs 源码解析(三):插件(上)
- dayjs 源码解析(四):插件(中)
- dayjs 源码解析(五):插件(下)
手写一个 Dayjs 插件
作为一个示范插件,应该尽量实现简单。咱们就来动手写一个按照指定范围随机取一个时刻的方法。
插件设计
- 实现静态方法
randBetween,必传参数为2个时刻,返回2个时刻间的1个随机时刻。 - 实现类实例的原型方法
randBetween, 必传参数为1个时刻,返回该时刻与实例时刻间的1个随机时刻。 - 入参的时刻类型可以为
Dayjs实例、Date实例或13位时间戳,返回的时刻类型为Dayjs实例。
实现
实现的思路如下:
- 两个时刻统一封装为
Dayjs实例 - 取到两个时刻的
13位时间戳。(valueOf) - 计算两个时间戳内的随机整数
- 将随机事件封装为
Dayjs实例返回
工具函数:计算随机整数
按照计算机科学的惯例,应当使用前闭后开。
/**
* @description: 计算随机整数
* @param {Number} min 最大值
* @param {Number} max 最小值
* @return {Number} 前闭后开
*/
const random = (min, max) => Math.floor(Math.random() * (max - min)) + min;
工具函数:求随机时刻
dayjs().valueOf() 方法可以直接取到 13 位的时间戳。
/**
* @description: 计算随机时刻
* @param {Dayjs| Date | Number} ref1 两端时刻
* @param {Dayjs| Date | Number} ref2 两端时刻
* @return {Dayjs} 返回一个Dayjs实例
*/
const between = (ref1, ref2) => {
let val1 = dayjs(ref1).valueOf();
let val2 = dayjs(ref2).valueOf();
let randomResult = random(...[val1, val2].sort((a, b) => a - b));
return dayjs(randomResult);
};
挂载到 dayjs 函数对象和类实例原型上
最后一步,就是将方法挂载到需要的地方。挂载到原型上时需要注意不可以用箭头函数,因为需要 this 指向实例。
/**
* @description: plugin
* @param {Object} option option
* @param {Class} Dayjs Dayjs类
* @param {Function} dayjs dayjs函数对象
*/
let dayjsRandom = (option, Dayjs, dayjs) => {
const random = (min, max) => Math.floor(Math.random() * (max - min)) + min;
const between = (ref1, ref2) => {
let val1 = dayjs(ref1).valueOf();
let val2 = dayjs(ref2).valueOf();
let randomResult = random(...[val1, val2].sort((a, b) => a - b));
return dayjs(randomResult);
};
Dayjs.prototype.randBetween = function (ref) {
return between(this, ref);
};
dayjs.randBetween = (ref1, ref2) => between(ref1, ref2);
};
测试
2021年1月1日0时0分0秒的 13 位时间戳为 1609430400000。
// 挂载插件
dayjs.extend(dayjsRandom);
// 实例测试
dayjs().randomBetween(new Date(1609430400000)).format(); // output: 2021-01-27T06:53:42+08:00
dayjs().randomBetween(dayjs(1609430400000)).format(); // output: 2021-02-04T02:56:27+08:00
dayjs().randomBetween(1609430400000).format(); // output: 2021-01-22T02:38:09+08:00
// 函数对象测试
dayjs.randomBetween(new Date(), 1609430400000).format(); // output: 2021-01-04T01:30:56+08:00
三种格式的输出都没有问题。
总结
dayjs 源码解析系列完成 🎉。该系列先解析了关于时间的一些概念,又分解了 dayjs 项目的结构并分析了 Dayjs类 的源码,再解析了各个插件的源码,最后手动实现了一个插件。
前端记事本,不定期更新,欢迎关注!