wallleap / myblogs

blog, Issue
https://myblog.wallleap.cn
4 stars 1 forks source link

实现一个 JS 时间库 #96

Closed wallleap closed 1 year ago

wallleap commented 1 year ago

使用 AI 辅助实现一个好用的 JS 时间库

来自你的消息:

你是一个前端高级工程师,我有一些前端的问题想问你,请你回答

来自 去问AI 的消息:

好的,请问你有哪些前端问题需要我回答呢?

来自你的消息:

前端封装有哪几种方式,技巧有哪些

来自 去问AI 的消息:

前端封装的方式有以下几种:

  1. 函数封装:将一些功能封装成函数,通过调用函数来实现该功能。

  2. 对象封装:将一些相关功能封装成一个对象,通过对象的方法来调用封装的功能。

  3. 组件化封装:将一些可复用的 HTML/CSS/JS 代码封装成一个组件,通过简单的 API 调用来使用这个组件。

技巧方面,前端封装可以参考以下几点:

  1. 抽象出公共部分:将一些公共的逻辑抽象出来,封装成一个通用的函数或对象。

  2. 开放性设计:在封装的接口中,应该尽可能开放更多的自定义参数和回调函数,让使用者根据自己的需求调用。

  3. 细化模块的功能:将模块分解成更小的模块,每个模块负责完成更明确的功能,保证代码的可维护性。

  4. 注意兼容性:在封装时应该考虑到浏览器的兼容性问题,并尽可能地采用通用的、兼容多个浏览器的解决方案。

  5. 维护文档:在封装完成后,应该编写文档详细描述功能和使用方法,以便后续的维护和使用。

来自你的消息:

来一个函数封装案例

来自 去问AI 的消息:

好的,以下是一个简单的函数封装案例:

// 将一个字符串反转
function reverseString(str) {
  var reversed = "";
  for (var i = str.length - 1; i >= 0; i--) {
    reversed += str[i];
  }
  return reversed;
}

上面的函数封装了一个将字符串反转的功能,通过传入一个字符串参数,函数会返回一个反转后的字符串。该函数使用了一个 for 循环来遍历原字符串并逆序添加字符到一个新的字符串内,最后返回这个新的字符串。这个函数可以在任何需要字符串反转的地方使用,不需要再次编写反转代码。

来自你的消息:

对象封装案例

来自 去问AI 的消息:

好的,以下是一个简单的对象封装案例:

// 定义一个存储数据的对象
var Storage = {
  set: function(key, value) {
    localStorage.setItem(key, JSON.stringify(value));
  },
  get: function(key) {
    var value = localStorage.getItem(key);
    return value && JSON.parse(value);
  },
  remove: function(key) {
    localStorage.removeItem(key);
  }
};

上面的代码封装了一个存储数据到本地的功能,通过定义一个名为 Storage 的对象,该对象封装了 set、get 和 remove 三个方法。set 方法通过调用 localStorage 的 setItem 方法存储数据,get 方法通过调用 localStorage 的 getItem 方法获取数据,并使用 JSON 对象对数据进行序列化与反序列化,remove 方法通过调用 localStorage 的 removeItem 方法删除数据。使用该对象可以很方便地操作浏览器本地存储,减少了代码的重复性和冗余性。使用方式如下:

Storage.set("username", "John");
var username = Storage.get("username");
Storage.remove("username");

上面的代码中,首先使用 set 方法将用户名存储到本地,然后使用 get 方法获取存储在本地的用户名,并将其赋值给变量 username,最后使用 remove 方法删除用户名的本地存储。

来自你的消息:

组件化封装案例

来自 去问AI 的消息:

好的,以下是一个简单的组件化封装案例:

// 定义一个 Toast 组件
var Toast = {
  show: function(message, duration) {
    duration = duration || 2000;
    var toast = document.createElement("div");
    toast.classList.add("toast");
    toast.innerHTML = message;
    document.body.appendChild(toast);
    setTimeout(function() {
      document.body.removeChild(toast);
    }, duration);
  }
};

上面的代码封装了一个 Toast 组件,该组件可以在页面上显示一个短暂的提示信息并自动消失。Toast 组件定义了 show 方法,通过传入消息及持续时间(默认为 2 秒),创建一个 div 元素,设置样式及消息内容,并将该元素添加到页面中。然后通过 setTimeout 函数实现在指定时间后自动消失。使用该组件可以很方便地在页面中显示各种提示信息,提高用户交互的友好性。使用方式如下:

Toast.show("提交成功");
Toast.show("请先登录", 5000); // 持续 5 秒

上面的代码中,首先通过 show 方法显示提交成功的提示信息,并默认持续 2 秒后自动消失。然后通过 show 方法再次显示提示信息(请先登录),并设置持续时间为 5 秒。

来自你的消息:

我想封装一个类似 day.js 的时间库,名称是 time.js,请给我一个 class 封装模板

来自 去问AI 的消息:

好的,这是一个简单的 time.js 的类封装模板:

class Time {
  constructor() {
    // 在构造函数中初始化时间对象
    this.date = new Date();
  }

  // 获取当前时间的方法
  now() {
    return this.date;
  }

  // 将时间格式化为指定格式的方法
  format(formatString) {
    // 实现格式化逻辑
    // ...
  }

  // 在当前时间上增加指定时间的方法
  add(amount, unit) {
    // 实现时间增加逻辑
    // ...
  }

  // 在当前时间上减少指定时间的方法
  subtract(amount, unit) {
    // 实现时间减少逻辑
    // ...
  }
}

// 导出 Time 类
export default Time;

上面的代码定义了一个 Time 类,该类封装了当前时间的获取、时间格式化、时间增加和时间减少等方法。在构造函数中初始化了时间对象,可以使用该类的 now 方法获取当前时间,使用 format 方法将时间格式化为指定格式,使用 add 和 subtract 方法在当前时间上增加或减少指定的时间。当然,这个只是一个简单的类封装模板,你可以根据自己的需求添加更多的方法和功能。如果需要在浏览器环境下使用该类,那么需要将导出方式更改为普通的导出方式:

// 导出 Time 类
module.exports = Time;

来自你的消息:

我需要在这个时间库中加入一个返回时间戳的函数

来自 去问AI 的消息:

好的,你可以在 Time 类中添加一个方法来返回时间戳,如下所示:

class Time {
  constructor() {
    // 在构造函数中初始化时间对象
    this.date = new Date();
  }

  // 获取当前时间的方法
  now() {
    return this.date;
  }

  // 将时间格式化为指定格式的方法
  format(formatString) {
    // 实现格式化逻辑
    // ...
  }

  // 在当前时间上增加指定时间的方法
  add(amount, unit) {
    // 实现时间增加逻辑
    // ...
  }

  // 在当前时间上减少指定时间的方法
  subtract(amount, unit) {
    // 实现时间减少逻辑
    // ...
  }

  // 返回当前时间戳的方法
  timestamp() {
    return this.date.getTime();
  }
}

// 导出 Time 类
export default Time;

上面的代码中,我们添加了一个 timestamp 方法,该方法返回当前时间的时间戳,可以使用该方法获取当前时间的毫秒数。

来自你的消息:

实现一下 format 方法

来自 去问AI 的消息:

好的,这是一个时间格式化的简单例子,你可以将其添加到 Time 类的 format 方法中:

// 将时间格式化为指定格式的方法
format(formatString) {
  const year = this.date.getFullYear();
  const month = this.date.getMonth() + 1;
  const date = this.date.getDate();
  const hours = this.date.getHours();
  const minutes = this.date.getMinutes();
  const seconds = this.date.getSeconds();

  return formatString
    .replace(/YYYY/g, year)
    .replace(/MM/g, month < 10 ? `0${month}` : month)
    .replace(/DD/g, date < 10 ? `0${date}` : date)
    .replace(/hh/g, hours < 10 ? `0${hours}` : hours)
    .replace(/mm/g, minutes < 10 ? `0${minutes}` : minutes)
    .replace(/ss/g, seconds < 10 ? `0${seconds}` : seconds);
}

上面的代码中,我们通过 Date 对象的一些方法获取了年份、月份、日期、小时、分钟和秒钟等信息,并使用正则表达式将指定的格式字符串中的占位符替换为对应的时间信息,从而实现了一个简单的时间格式化功能。当然,你可以根据自己的需求扩展更多的占位符和时间格式支持。

来自你的消息:

让 format 支持更多格式

来自 去问AI 的消息:

好的,我们可以继续扩展 format 方法,让其支持更多的时间格式。下面是一个比较全面的时间格式支持,“YYYY-MM-DD hh:mm:ss” 是默认格式:

// 将时间格式化为指定格式的方法
format(formatString = 'YYYY-MM-DD hh:mm:ss') {
  const year = this.date.getFullYear();
  const month = this.date.getMonth() + 1;
  const date = this.date.getDate();
  const hours = this.date.getHours();
  const minutes = this.date.getMinutes();
  const seconds = this.date.getSeconds();
  const milliseconds = this.date.getMilliseconds();

  return formatString
    .replace(/YY/g, year.toString().substr(2))
    .replace(/YYYY/g, year)
    .replace(/M/g, month)
    .replace(/MM/g, month < 10 ? `0${month}` : month)
    .replace(/D/g, date)
    .replace(/DD/g, date < 10 ? `0${date}` : date)
    .replace(/h/g, hours)
    .replace(/hh/g, hours < 10 ? `0${hours}` : hours)
    .replace(/m/g, minutes)
    .replace(/mm/g, minutes < 10 ? `0${minutes}` : minutes)
    .replace(/s/g, seconds)
    .replace(/ss/g, seconds < 10 ? `0${seconds}` : seconds)
    .replace(/SSS/g, milliseconds);
}

在这个实现中,我们根据所需的时间格式,使用正则表达式匹配替换占位符,以获取所需的时间信息。例如,使用 /YYYY/g 替换为实际的年份,使用 /MM/g 替换为实际的月份,以此类推。注意,我们还支持了毫秒的格式化,使用 /SSS/g 占位符即可。你可以根据自己的需求,扩展更多的占位符和时间格式。

来自你的消息:

只有一个 s 是什么意思

来自 去问AI 的消息:

当我们将占位符 /s/g 使用正则表达式来替换为实际的秒钟数时,它只会匹配格式中仅出现一次的 s 字符。这种情况下,会匹配例如:“2022-01-01 1:1:1” 或者 “2022-01-01 12:2:2” 的时间格式中的秒钟数。在这种情况下,我们假定时间格式中仅出现一次 s 字符代表秒钟数。

但实际上,为了避免歧义,一般建议秒钟数的占位符使用 ss 而不是 s,以避免出现上述问题。如果时间格式中出现多个 s 字符,我们需要将它们全部替换为对应的秒钟数,否则可能会出现时间格式错误的问题。

来自你的消息:

s 是两位的时候会怎样显示

来自 去问AI 的消息:

如果你的时间格式中需要秒钟数显示两位数,你可以使用占位符 ss 来代表秒钟数。在上面的代码实现中,我们已经支持了使用 ss 占位符代表秒钟数,并使用了以下的代码来进行替换:

.replace(/ss/g, seconds < 10 ? `0${seconds}` : seconds)

这个代码会把所有的 ss 占位符 替换成两位的秒钟数。如果秒钟数小于10,则在前面添加一个 0 来补齐两位数。例如,如果时间的秒钟数为 9,则使用上述代码替换后,它将显示为字符串 "09"。如果秒钟数为大于等于10的数字,则不需要在其前面添加0。

总的来说,在使用 ss 占位符时,我们需要确保时间格式中的秒钟数占位符与所需的时间格式对应匹配,这样才能正确地显示出两位数的秒钟数。

来自你的消息:

go 支持的 format 时间有哪些,你能全部都使用 js 实现吗

来自 去问AI 的消息:

Go 时间格式化占位符和 JavaScript 有一些区别,但是大部分的格式化都是相似的。下面是 Go 支持的一些时间格式化占位符:

格式化符号 描述
2006 年份,示例:2006
01 月份,示例:01~12
Jan 月份(英文缩写),示例:Jan、Feb...
02 日期,示例:01~31
Mon 星期几(英文缩写),示例:Mon、Tue...
03 小时(12小时制),示例:01~12
3 小时(12小时制),示例:1~12
15 小时(24小时制),示例:00~23
04 分钟,示例:00~59
05 秒钟,示例:00~59
PM/AM 上下午

注意,这里只列出了 Go 支持的一部分时间格式化占位符,还有很多占位符并没有列出。

虽然 Go 和 JavaScript 的时间格式化占位符有所区别,但是通过使用正则表达式和 JavaScript 的 Date 对象方法,我们仍然可以实现大部分的 Go 时间格式化占位符。下面是一个例子:

function formatGoTime(date, formatString) {
  const year = date.getFullYear();
  const month = date.getMonth() + 1;
  const day = date.getDate();
  const hour = date.getHours();
  const minute = date.getMinutes();
  const second = date.getSeconds();

  // 映射 Go 时间格式化占位符和替换函数
  const replacements = {
    '2006': () => year,
    '01': () => month < 10 ? `0${month}` : month,
    'Jan': () => getEnglishMonthAbbr(month),
    '02': () => day < 10 ? `0${day}` : day,
    'Mon': () => getEnglishWeekdayAbbr(date),
    '03': () => hour % 12 || 12,
    '3': () => hour % 12 || 12,
    '15': () => hour < 10 ? `0${hour}` : hour,
    '04': () => minute < 10 ? `0${minute}` : minute,
    '05': () => second < 10 ? `0${second}` : second,
    'PM': () => hour >= 12 ? 'PM' : 'AM',
    'pm': () => hour >= 12 ? 'pm' : 'am'
  }

  return formatString.replace(/\d{2}|\d{4}|Jan|Mon|PM|pm/g, match => {
    const replacement = replacements[match];
    return replacement ? replacement() : match;
  });
}

// 获取英文月份的缩写
function getEnglishMonthAbbr(month) {
  const months = [
    'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug',
    'Sep', 'Oct', 'Nov', 'Dec'
  ];
  return months[month - 1];
}

// 获取英文星期几的缩写
function getEnglishWeekdayAbbr(date) {
  const weekdays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
  return weekdays[date.getDay()];
}

在这个例子中,我们定义了一个 formatGoTime 函数,传入一个 Date 对象和一个 Go 时间格式化字符串,将时间对象格式化为 Go 所需的时间格式。我们使用一个 replacements 对象存储 Go 时间格式化占位符和对应的替换函数,并使用正则表达式去匹配格式化字符串中出现的占位符,然后根据占位符对应的替换函数来替换时间对象为格式化字符串。

需要注意的是,在这个例子中只实现了 Go 一部分的时间格式化占位符,并且对于一些时间格式化占位符的替换方式可能还可以优化。如果你需要支持更多的时间格式化占位符,可以根据上面的例子进行扩展和实现。

来自你的消息:

更多的时间库功能

来自 去问AI 的消息:

除了可以格式化时间字符串,JavaScript 时间库还提供了很多其他有用的功能,例如:

1. 解析时间字符串

JavaScript 的 Date 对象可以通过接收一个时间字符串来被创建,例如:

const date = new Date("2022/01/01 00:00:00");

这个例子中,我们传入了一个时间字符串 "2022/01/01 00:00:00"Date 构造函数,创建了一个代表 2022 年 1 月 1 日 0 点的时间对象。

如果你的时间字符串格式不是标准格式,可以使用第三方库如 moment.jsday.js 来进行解析。

2. 时间戳转换

JavaScript 的 Date 对象可以将时间戳(从 1970 年 1 月 1 日开始到某一时间点的毫秒数)转换为时间对象:

const timestamp = Date.now(); // 当前时间戳(毫秒数)
const date = new Date(timestamp);

这个例子中,我们使用 Date.now() 方法获取当前时间的时间戳,然后将其传递给 Date 构造函数,创建了一个代表当前时间的时间对象。

JavaScript 的 Date 对象也可以将时间对象转换为时间戳:

const date = new Date("2022/01/01 00:00:00");
const timestamp = date.getTime();

这个例子中,我们创建了一个代表 2022 年 1 月 1 日 0 点的时间对象,然后使用 getTime() 方法获取其时间戳(毫秒数)。

3. 时间计算

JavaScript 的 Date 对象提供了一些便捷的方法来进行时间计算,例如:

const date1 = new Date("2022/01/01 00:00:00");
const date2 = new Date("2022/01/02 00:00:00");

// 计算两个时间之间相差的毫秒数
const diff = date2 - date1; // 86400000(一天的毫秒数)

这个例子中,我们创建了两个时间对象 date1date2,代表 2022 年 1 月 1 日 0 点和 2022 年 1 月 2 日 0 点,然后计算它们之间相差的毫秒数。

你也可以使用 JavaScript 的 day.jsdate-fns 等第三方库来进行更方便的时间计算。

4. 时区处理

JavaScript 的 Date 对象默认使用本地时区,但是可以通过设置时区偏移量来处理不同时区的时间。例如:

// 获取一个指定时区偏移量的时间对象
const offset = -8; // 时区偏移量(以小时为单位),例如 -8 表示 GMT-8 时区
const date = new Date(Date.now() + (offset * 60 * 60 * 1000));

这个例子中,我们使用 Date.now() 获取当前的时间戳,然后加上一个表示时区偏移量的毫秒数来获取指定时区的时间对象。

JavaScript 本身并没有提供专门的时区处理相关的 API,但是有些第三方库,如 moment.jsday.js,可以提供更方便的时区处理功能。

总的来说,JavaScript 时间库提供了很多有用的功能,可以满足大部分的时间处理需求。同时,也有很多第三方时间库可以帮助你更方便地处理时间相关问题。