最近翻到 ElementUI 的日期组件源码,看到一些处理日期的工具方法,挺有意思,平常没有注意到,特此记录下来。
获取当前日期的前一天,后一天
export const prevDate = function(date, amount = 1) {
return new Date(date.getFullYear(), date.getMonth(), date.getDate() - amount);
};
export const nextDate = function(date, amount = 1) {
return new Date(date.getFullYear(), date.getMonth(), date.getDate() + amount);
};
这里获取当前日期的前一天用的是 date.getDate() - 1
而不是 date.getTime() - 24 * 60 * 60 * 1000
是为了避免在夏令时转换时导致的错误。
在某些国家,比如英国,每年都会实行夏令时制。
所以在夏令时起止当天如果用 date.getTime() (+)- 24 * 60 * 60 * 1000
获取前一天后一天可能会导致错误。
创建包含 1-N 的数组
Element 的做法是利用 Function.prototype.apply
的第二个参数可以是类数组对象来实现;
export const range = function(n) {
return Array.apply(null, {length: n}).map((_, n) => n);
};
上面的 Array.apply(null, {length: n})
将会创造 n
个值为 undefined
的数组,再利用 map
函数一个个改变数组值;
还有很多种实现方法,而且有比上面执行速度更快的方法;
(1)Array.from()
// 第一种
Array.from(Array(N), (_, i) => i+1)
// 第二种
Array.from({length: N}, (_, i) => i + 1)
// 第三种
Array.from({length:N}, Number.call, i => i + 1)
Array.from()
可以通过 可迭代对象 和 类数组对象(带有 length
属性和索引元素的对象) 来创建数组;
并且如果 类数组对象 只有length
属性没有索引元素,那么创建的数组值都为 undefined
参考
Array.from()
的第二个参数为一个可选的 mapFn
,类似于数组 map
函数;但不同的是Array.from()
的 mapFn
会对空槽元素执行回调函数;上面方式的比 Array.apply(null, {length: n}).map((_, n) => n);
的优势是不会创建中间数组;
第三种方法,第三个参数是一个函数,会被 Number.call
当作 this
调用
(2)while 循坏
let i=0, a=Array(N);
while(i<N) a[i++]=i;
(3)for 循环
var foo = [];
for (var i = 1; i <= N; i++) {
foo.push(i);
}
(4)Array.prototype.fill
Array(N).fill().map((_, i) => i+1);
和 Array.from()
类似,Array(N).fill()
也会创建 N
个值为 undefined
的数组;
(5)Array(N).join().split(',')
Array(N).join().split(',').map((_, i) => i+1 );
Array(N)
会创建 N
个空槽组成的数组,空槽既不是 undefined
,也不是空字符串;并且 map
也不会对空槽元素执行回调函数,所以需要通过 Array(N).join().split(',')
将会得到 N
个字符串组成的数组;
(6)扩展运算符
[...Array(N).keys()].map(x => x + 1);
[...Array(N+1).keys()].slice(1)
[...Array(N)]
扩展运算符会将空槽元素转化为 undefined
(7)Uint8Array
new Uint8Array(5).map((item, i) => i + 1);
性能
对以上方式进行性能测试,测试工具是 jsbench ,测试的的浏览器版本是谷歌 115.0.5790.110(正式版本) (64 位)
结果如下
设置初始值 N 为 1000000,ops 为每秒操作数,图中结果按照从高到低排序;while
循环最快