275 个最喜欢的JavaScript实用工具

只用一行代码!没有更多!

GitHub 英文源站
Array

将值转换为数组
#

const castArray = (value) => (Array.isArray(value) ? value : [value]);

// Examples
castArray(1); // [1]
castArray([1, 2, 3]); // [1, 2, 3]

检查数组是否为空
#

// `arr` is an array
const isEmpty = (arr) => !Array.isArray(arr) || arr.length === 0;

// Examples
isEmpty([]); // true
isEmpty([1, 2, 3]); // false

克隆数组
#

// `arr` is an array
const clone = (arr) => arr.slice(0);

// Or
const clone = (arr) => [...arr];

// Or
const clone = (arr) => Array.from(arr);

// Or
const clone = (arr) => arr.map((x) => x);

// Or
const clone = (arr) => JSON.parse(JSON.stringify(arr));

// Or
const clone = (arr) => arr.concat([]);

比较两个数组,而不考虑顺序
#

// `a` and `b` are arrays
const isEqual = (a, b) => JSON.stringify(a.sort()) === JSON.stringify(b.sort());

// Examples
isEqual([1, 2, 3], [1, 2, 3]); // true
isEqual([1, 2, 3], [1, 3, 2]); // true
isEqual([1, 2, 3], [1, "2", 3]); // false

比较两个数组
#

// `a` and `b` are arrays
const isEqual = (a, b) => JSON.stringify(a) === JSON.stringify(b);

// Or
const isEqual = (a, b) =>
a.length === b.length && a.every((v, i) => v === b[i]);

// Examples
isEqual([1, 2, 3], [1, 2, 3]); // true
isEqual([1, 2, 3], [1, "2", 3]); // false

将对象数组转换为单个对象
#

const toObject = (arr, key) =>
arr.reduce((a, b) => ({ ...a, [b[key]]: b }), {});

// Example
toObject(
[
{ id: "1", name: "Alpha", gender: "Male" },
{ id: "2", name: "Bravo", gender: "Male" },
{ id: "3", name: "Charlie", gender: "Female" },
],
"id"
);
/*
{
'1': { id: '1', name: 'Alpha', gender: 'Male' },
'2': { id: '2', name: 'Bravo', gender: 'Male' },
'3': { id: '3', name: 'Charlie', gender: 'Female' },
}
*/

将字符串数组转换为数字
#

const toNumbers = (arr) => arr.map(Number);

// Or
const toNumbers = (arr) => arr.map((x) => +x);

// Example
toNumbers(["2", "3", "4"]); // [2, 3, 4]

通过对象数组的属性进行计数
#

const countBy = (arr, prop) =>
arr.reduce(
(prev, curr) => ((prev[curr[prop]] = ++prev[curr[prop]] || 1), prev),
{}
);

// Example
countBy(
[
{ branch: "audi", model: "q8", year: "2019" },
{ branch: "audi", model: "rs7", year: "2020" },
{ branch: "ford", model: "mustang", year: "2019" },
{ branch: "ford", model: "explorer", year: "2020" },
{ branch: "bmw", model: "x7", year: "2020" },
],
"branch"
);

// { 'audi': 2, 'ford': 2, 'bmw': 1 }

计算数组中某个值的出现
#

const countOccurrences = (arr, val) =>
arr.reduce((a, v) => (v === val ? a + 1 : a), 0);

// Or
const countOccurrences = (arr, val) =>
arr.filter((item) => item === val).length;

// Examples
countOccurrences([2, 1, 3, 3, 2, 3], 2); // 2
countOccurrences(["a", "b", "a", "c", "a", "b"], "a"); // 3

计算数组元素的出现
#

const countOccurrences = (arr) =>
arr.reduce((prev, curr) => ((prev[curr] = ++prev[curr] || 1), prev), {});

// Examples
countOccurrences([2, 1, 3, 3, 2, 3]); // { '1': 1, '2': 2, '3': 3 }
countOccurrences(["a", "b", "a", "c", "a", "b"]); // { 'a': 3, 'b': 2, 'c': 1 }

创建一个累加和数组
#

const accumulate = (arr) =>
arr.map(
(
(sum) => (value) =>
(sum += value)
)(0)
);

// Or
const accumulate = (arr) =>
arr.reduce((a, b, i) => (i === 0 ? [b] : [...a, b + a[i - 1]]), []);

// Or
const accumulate = (arr) =>
arr.reduce((a, b, i) => (i === 0 ? [b] : [...a, b + a[i - 1]]), 0);

// Example
accumulate([1, 2, 3, 4]); // [1, 3, 6, 10]
// 1 = 1
// 1 + 2 = 3
// 1 + 2 + 3 = 6
// 1 + 2 + 3 + 4 = 10

在给定范围内创建一个数字数组
#

const range = (min, max) =>
[...Array(max - min + 1).keys()].map((i) => i + min);

// Or
const range = (min, max) =>
Array(max - min + 1)
.fill(0)
.map((_, i) => min + i);

// Or
const range = (min, max) =>
Array.from({ length: max - min + 1 }, (_, i) => min + i);

// Example
range(5, 10); // [5, 6, 7, 8, 9, 10]

创建笛卡尔积
#

const cartesian = (...sets) =>
sets.reduce(
(acc, set) => acc.flatMap((x) => set.map((y) => [...x, y])),
[[]]
);

// Example
cartesian([1, 2], [3, 4]); // [ [1, 3], [1, 4], [2, 3], [2, 4] ]

/*
3 4
---------------
1 | [1, 3] [1, 4]
|
2 | [2, 3] [2, 4]

*/

清空数组
#

const empty = (arr) => (arr.length = 0);

// Or
arr = [];

从数组中找到最接近的数字
#

// Find the number from `arr` which is closest to `n`
const closest = (arr, n) =>
arr.reduce((prev, curr) =>
Math.abs(curr - n) < Math.abs(prev - n) ? curr : prev
);

// Or
const closest = (arr, n) =>
arr.sort((a, b) => Math.abs(a - n) - Math.abs(b - n))[0];

// Example
closest([29, 87, 8, 78, 97, 20, 75, 33, 24, 17], 50); // 33

查找数组中最后一个匹配项的索引
#

const lastIndex = (arr, predicate) =>
arr.reduce((prev, curr, index) => (predicate(curr) ? index : prev), -1);

// Or
const lastIndex = (arr, predicate) =>
arr.map((item) => predicate(item)).lastIndexOf(true);

// Example
lastIndex([1, 3, 5, 7, 9, 2, 4, 6, 8], (i) => i % 2 === 1); // 4
lastIndex([1, 3, 5, 7, 9, 8, 6, 4, 2], (i) => i > 6); // 5

查找数组中最大项的索引
#

const indexOfMax = (arr) =>
arr.reduce((prev, curr, i, a) => (curr > a[prev] ? i : prev), 0);

// Examples
indexOfMax([1, 3, 9, 7, 5]); // 2
indexOfMax([1, 3, 7, 7, 5]); // 2

查找数组最小项的索引
#

const indexOfMin = (arr) =>
arr.reduce((prev, curr, i, a) => (curr < a[prev] ? i : prev), 0);

// Examples
indexOfMin([6, 4, 8, 2, 10]); // 3
indexOfMin([6, 4, 2, 2, 10]); // 2

查找数组中最长字符串的长度
#

const findLongest = (words) => Math.max(...words.map((el) => el.length));

// Example
findLongest(["always", "look", "on", "the", "bright", "side", "of", "life"]); // 6

通过给定键找到数组的最大项
#

const maxBy = (arr, key) =>
arr.reduce((a, b) => (a[key] >= b[key] ? a : b), {});

// Example
const people = [
{ name: "Bar", age: 24 },
{ name: "Baz", age: 32 },
{ name: "Foo", age: 42 },
{ name: "Fuzz", age: 36 },
];
maxBy(people, "age"); // { name: 'Foo', age: 42 }

查找数组的最大项
#

const max = (arr) => Math.max(...arr);

通过给定键找到数组的最小项
#

const minBy = (arr, key) => arr.reduce((a, b) => (a[key] < b[key] ? a : b), {});

// Example
const people = [
{ name: "Bar", age: 24 },
{ name: "Baz", age: 32 },
{ name: "Foo", age: 42 },
{ name: "Fuzz", age: 36 },
];
minBy(people, "age"); // { name: 'Bar', age: 24 }

查找数组的最小项
#

const min = (arr) => Math.min(...arr);

展平数组
#

const flat = (arr) =>
[].concat.apply(
[],
arr.map((a) => (Array.isArray(a) ? flat(a) : a))
);
// Or
const flat = (arr) =>
arr.reduce((a, b) => (Array.isArray(b) ? [...a, ...flat(b)] : [...a, b]), []);

// Or
// See the browser compatibility at https://caniuse.com/#feat=array-flat
const flat = (arr) => arr.flat();

// Example
flat(["cat", ["lion", "tiger"]]); // ['cat', 'lion', 'tiger']

获取所有连续元素的数组
#

const getConsecutiveArrays = (arr, size) =>
size > arr.length
? []
: arr.slice(size - 1).map((_, i) => arr.slice(i, size + i));

// Examples
getConsecutiveArrays([1, 2, 3, 4, 5], 2); // [[1, 2], [2, 3], [3, 4], [4, 5]]
getConsecutiveArrays([1, 2, 3, 4, 5], 3); // [[1, 2, 3], [2, 3, 4], [3, 4, 5]]
getConsecutiveArrays([1, 2, 3, 4, 5], 6); // []

获取数组的所有n项
#

const getNthItems = (arr, nth) => arr.filter((_, i) => i % nth === nth - 1);

// Examples
getNthItems([1, 2, 3, 4, 5, 6, 7, 8, 9], 2); // [2, 4, 6, 8]
getNthItems([1, 2, 3, 4, 5, 6, 7, 8, 9], 3); // [3, 6, 9]

获取数组的所有子集
#

const getSubsets = (arr) =>
arr.reduce(
(prev, curr) => prev.concat(prev.map((k) => k.concat(curr))),
[[]]
);

// Examples
getSubsets([1, 2]); // [[], [1], [2], [1, 2]]
getSubsets([1, 2, 3]); // [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]

获取数组中值的索引
#

const indices = (arr, value) =>
arr.reduce((acc, v, i) => (v === value ? [...acc, i] : acc), []);

// Or
const indices = (arr, value) =>
arr.map((v, i) => (v === value ? i : false)).filter(Boolean);

// Examples
indices(["h", "e", "l", "l", "o"], "l"); // [2, 3]
indices(["h", "e", "l", "l", "o"], "w"); // []

获取数组的平均值
#

const average = (arr) => arr.reduce((a, b) => a + b, 0) / arr.length;

获取数组的交集
#

const getIntersection = (a, ...arr) =>
[...new Set(a)].filter((v) => arr.every((b) => b.includes(v)));

// Examples
getIntersection([1, 2, 3], [2, 3, 4, 5]); // [2, 3]
getIntersection([1, 2, 3], [2, 3, 4, 5], [1, 3, 5]); // [3]

获取一个数字数组的等级
#

const ranking = (arr) =>
arr.map((x, y, z) => z.filter((w) => w > x).length + 1);

// Examples
ranking([80, 65, 90, 50]); // [2, 3, 1, 4]
ranking([80, 80, 70, 50]); // [1, 1, 3, 4]
ranking([80, 80, 80, 50]); // [1, 1, 1, 4]

获得一个数字数组的和
#

const sum = (arr) => arr.reduce((a, b) => a + b, 0);

获取数组的唯一值
#

const unique = (arr) => [...new Set(arr)];

// Or
const unique = (arr) => arr.filter((el, i, array) => array.indexOf(el) === i);

// Or
const unique = (arr) =>
arr.reduce((acc, el) => (acc.includes(el) ? acc : [...acc, el]), []);

获得数组的并集
#

const union = (...arr) => [...new Set(arr.flat())];

// Example
union([1, 2], [2, 3], [3]); // [1, 2, 3]

通过键将对象数组进行分组
#

const groupBy = (arr, key) =>
arr.reduce(
(acc, item) => ((acc[item[key]] = [...(acc[item[key]] || []), item]), acc),
{}
);

// Example
groupBy(
[
{ branch: "audi", model: "q8", year: "2019" },
{ branch: "audi", model: "rs7", year: "2020" },
{ branch: "ford", model: "mustang", year: "2019" },
{ branch: "ford", model: "explorer", year: "2020" },
{ branch: "bmw", model: "x7", year: "2020" },
],
"branch"
);

/*
{
audi: [
{ branch: 'audi', model: 'q8', year: '2019' },
{ branch: 'audi', model: 'rs7', year: '2020' }
],
bmw: [
{ branch: 'bmw', model: 'x7', year: '2020' }
],
ford: [
{ branch: 'ford', model: 'mustang', year: '2019' },
{ branch: 'ford', model: 'explorer', year: '2020' }
],
}
*/

合并两个数组
#

// Merge but don't remove the duplications
const merge = (a, b) => a.concat(b);
// Or
const merge = (a, b) => [...a, ...b];

// Merge and remove the duplications
const merge = [...new Set(a.concat(b))];
// Or
const merge = [...new Set([...a, ...b])];

根据条件对数组进行分区
#

const partition = (arr, criteria) =>
arr.reduce((acc, i) => (acc[criteria(i) ? 0 : 1].push(i), acc), [[], []]);

// Example
partition([1, 2, 3, 4, 5], (n) => n % 2); // [[2, 4], [1, 3, 5]]

删除数组中的重复值
#

const removeDuplicate = (arr) =>
arr.filter((i) => arr.indexOf(i) === arr.lastIndexOf(i));

// Example
removeDuplicate(["h", "e", "l", "l", "o", "w", "o", "r", "l", "d"]); // ['h', 'e', 'w', 'r', 'd']

从数组中删除虚假值
#

const removeFalsy = (arr) => arr.filter(Boolean);

// Example
removeFalsy([
0,
"a string",
"",
NaN,
true,
5,
undefined,
"another string",
false,
]); // ['a string', true, 5, 'another string']

随机排列数组
#

const shuffle = (arr) =>
arr
.map((a) => ({ sort: Math.random(), value: a }))
.sort((a, b) => a.sort - b.sort)
.map((a) => a.value);

// Or
const shuffle = (arr) => arr.sort(() => 0.5 - Math.random());

// Example
shuffle([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); // [9, 1, 10, 6, 8, 5, 2, 3, 7, 4]

按给定键对项目数组进行排序
#

const sortBy = (arr, k) =>
arr.concat().sort((a, b) => (a[k] > b[k] ? 1 : a[k] < b[k] ? -1 : 0));

// Example
const people = [
{ name: "Foo", age: 42 },
{ name: "Bar", age: 24 },
{ name: "Fuzz", age: 36 },
{ name: "Baz", age: 32 },
];
sortBy(people, "age");

// returns
// [
// { name: 'Bar', age: 24 },
// { name: 'Baz', age: 32 },
// { name: 'Fuzz', age: 36 },
// { name: 'Foo', age: 42 },
// ]

对数字数组进行排序
#

const sort = (arr) => arr.sort((a, b) => a - b);

// Example
sort([1, 5, 2, 4, 3]); // [1, 2, 3, 4, 5]

将数组拆分为块
#

const chunk = (arr, size) =>
arr.reduce(
(acc, e, i) => (
i % size ? acc[acc.length - 1].push(e) : acc.push([e]), acc
),
[]
);

// Examples
chunk([1, 2, 3, 4, 5, 6, 7, 8], 3); // [[1, 2, 3], [4, 5, 6], [7, 8]]
chunk([1, 2, 3, 4, 5, 6, 7, 8], 4); // [[1, 2, 3, 4], [5, 6, 7, 8]]

交换矩阵的行和列
#

const transpose = (matrix) =>
matrix[0].map((col, i) => matrix.map((row) => row[i]));

// Or
const transpose = (matrix) =>
matrix[0].map((col, c) => matrix.map((row, r) => matrix[r][c]));

// Or
const transpose = (matrix) =>
matrix.reduce(
(prev, next) => next.map((item, i) => (prev[i] || []).concat(next[i])),
[]
);

// Example
transpose([
// [
[1, 2, 3], // [1, 4, 7],
[4, 5, 6], // [2, 5, 8],
[7, 8, 9], // [3, 6, 9],
]); // ]

交换两个数组项
#

// `i` must be less than `j`
const swapItems = (a, i, j) =>
(a[i] &&
a[j] && [
...a.slice(0, i),
a[j],
...a.slice(i + 1, j),
a[i],
...a.slice(j + 1),
]) ||
a;

// Example
swapItems([1, 2, 3, 4, 5], 1, 4); // [1, 5, 3, 4, 2]

解压缩数组的数组
#

const unzip = (arr) =>
arr.reduce(
(acc, c) => (c.forEach((v, i) => acc[i].push(v)), acc),
Array.from({ length: Math.max(...arr.map((a) => a.length)) }, (_) => [])
);

// Example
unzip([
["a", 1],
["b", 2],
["c", 3],
["d", 4],
["e", 5],
]); // [['a', 'b', 'c', 'd', 'e'], [1, 2, 3, 4, 5]]

/*
a 1
b 2
c 3
d 4
e 5
*/

压缩多个数组
#

const zip = (...arr) =>
Array.from({ length: Math.max(...arr.map((a) => a.length)) }, (_, i) =>
arr.map((a) => a[i])
);

// Example
zip(["a", "b", "c", "d", "e"], [1, 2, 3, 4, 5]); // [['a', 1], ['b', 2], ['c', 3], ['d', 4], ['e', 5]]

/*
Does it look like a zipper?
a 1
b 2
c 3
d 4
e 5
*/
DOM

检查一个元素是否是另一个元素的后代
#

const isDescendant = (child, parent) => parent.contains(child);

检查一个元素是否聚焦
#

const hasFocus = (ele) => ele === document.activeElement;

检查是否支持触摸事件
#

const touchSupported = () =>
"ontouchstart" in window ||
(window.DocumentTouch && document instanceof window.DocumentTouch);

检查用户是否滚动到页面底部
#

const isAtBottom = () =>
document.documentElement.clientHeight + window.scrollY >=
document.documentElement.scrollHeight;

检测Internet Explorer浏览器
#

const isIE = !!document.documentMode;

检测macOS浏览器
#

const isMacBrowser = /Mac|iPod|iPhone|iPad/.test(navigator.platform);

获取元素的所有同级
#

const siblings = (ele) =>
[].slice.call(ele.parentNode.children).filter((child) => child !== ele);

获取元素相对于文档的位置
#

const getPosition = (ele) => (
(r = ele.getBoundingClientRect()),
{ left: r.left + window.scrollX, top: r.top + window.scrollY }
);

// Example
getPosition(document.body); // { left: 0, top: 0 }

获取选定的文本
#

const getSelectedText = () => window.getSelection().toString();

返回上一个页面
#

history.back();

// Or
history.go(-1);

隐藏元素
#

// Pick the method that is suitable for your use case
const hide = (ele) => (ele.style.display = "none");

// Or
const hide = (ele) => (ele.style.visibility = "hidden");

// Or
const hide = (ele) => (ele.hidden = true);

在另一个元素之后插入一个元素
#

const insertAfter = (ele, anotherEle) =>
anotherEle.parentNode.insertBefore(ele, anotherEle.nextSibling);

// Or
const insertAfter = (ele, anotherEle) =>
anotherEle.insertAdjacentElement("afterend", ele);

在其他元素之前插入一个元素
#

const insertBefore = (ele, anotherEle) =>
anotherEle.parentNode.insertBefore(ele, anotherEle);

// Or
const insertBefore = (ele, anotherEle) =>
anotherEle.insertAdjacentElement("beforebegin", ele);

在元素后插入给定的HTML
#

const insertHtmlAfter = (html, ele) => ele.insertAdjacentHTML("afterend", html);

在元素之前插入给定的HTML
#

const insertHtmlBefore = (html, ele) =>
ele.insertAdjacentHTML("beforebegin", html);

重定向到另一个页面
#

const goTo = (url) => (location.href = url);

重新加载当前页面
#

const reload = () => location.reload();

// Or
const reload = () => (location.href = location.href);

替换元素
#

const replace = (ele, newEle) => ele.parentNode.replaceChild(newEle, ele);

滚动到页面顶部
#

const goToTop = () => window.scrollTo(0, 0);

序列化表单数据
#

const serialize = (formEle) =>
Array.from(new FormData(formEle)).reduce(
(p, [k, v]) =>
Object.assign({}, p, {
[k]: p[k] ? (Array.isArray(p[k]) ? p[k] : [p[k]]).concat(v) : v,
}),
{}
);

显示一个元素
#

const show = (ele) => (ele.style.display = "");

从给定文本中剥离HTML
#

const stripHtml = (html) =>
new DOMParser().parseFromString(html, "text/html").body.textContent || "";

切换元素
#

const toggle = (ele) =>
(ele.style.display = ele.style.display === "none" ? "block" : "none");

// Or
const toggle = (ele) => (ele.hidden = !ele.hidden);
Date Time

将AM PM后缀添加到一个小时
#

// `h` is an hour number between 0 and 23
const suffixAmPm = (h) =>
`${h % 12 === 0 ? 12 : h % 12}${h < 12 ? "am" : "pm"}`;

// Examples
suffixAmPm(0); // '12am'
suffixAmPm(5); // '5am'
suffixAmPm(12); // '12pm'
suffixAmPm(15); // '3pm'
suffixAmPm(23); // '11pm'

计算两个日期之间的差异天数
#

const diffDays = (date, otherDate) =>
Math.ceil(Math.abs(date - otherDate) / (1000 * 60 * 60 * 24));

// Example
diffDays(new Date("2014-12-19"), new Date("2020-01-01")); // 1839

计算两个日期之间的月数
#

const monthDiff = (startDate, endDate) =>
Math.max(
0,
(endDate.getFullYear() - startDate.getFullYear()) * 12 -
startDate.getMonth() +
endDate.getMonth()
);

// Example
monthDiff(new Date("2020-01-01"), new Date("2021-01-01")); // 12

比较两个日期
#

// `a` and `b` are `Date` instances
const compare = (a, b) => a.getTime() > b.getTime();

// Example
compare(new Date("2020-03-30"), new Date("2020-01-01")); // true

将日期转换为YYYY-MM-DD格式
#

// `date` is a `Date` object
const formatYmd = (date) => date.toISOString().slice(0, 10);

// Example
formatYmd(new Date()); // 2020-05-06

将秒转换为hh:mm:ss格式
#

// `s` is number of seconds
const formatSeconds = (s) => new Date(s * 1000).toISOString().substr(11, 8);

// Or
const formatSeconds = (s) =>
new Date(s * 1000).toUTCString().match(/(\d\d:\d\d:\d\d)/)[0];

// Or
const formatSeconds = (s) =>
[parseInt(s / 60 / 60), parseInt((s / 60) % 60), parseInt(s % 60)]
.join(":")
.replace(/\b(\d)\b/g, "0$1");

// Examples
formatSeconds(200); // 00:03:20
formatSeconds(500); // 00:08:20

从日期中提取年,月,日,小时,分钟,秒和毫秒
#

// `date` is a `Date` object
const extract = (date) =>
date
.toISOString()
.split(/[^0-9]/)
.slice(0, -1);

// `extract` is an array of [year, month, day, hour, minute, second, millisecond]

格式化给定语言环境的日期
#

// `date` is a `Date` object
// `locale` is a locale (en-US, pt-BR, for example)
const format = (date, locale) => new Intl.DateTimeFormat(locale).format(date);

// Example
format(new Date(), "pt-BR"); // 06/05/2020

获取当前日期的四分之一
#

const getQuarter = (d = new Date()) => Math.ceil((d.getMonth() + 1) / 3);

以秒为单位获取当前时间戳
#

const ts = () => Math.floor(new Date().getTime() / 1000);

从日期获取一年中的某天
#

// `date` is a Date object
const dayOfYear = (date) =>
Math.floor(
(date - new Date(date.getFullYear(), 0, 0)) / (1000 * 60 * 60 * 24)
);

// Example
dayOfYear(new Date(2020, 04, 16)); // 137

获取日期月份中的第一个日期
#

const getFirstDate = (d = new Date()) =>
new Date(d.getFullYear(), d.getMonth(), 1);

获取某月的最后一个日期
#

const getLastDate = (d = new Date()) =>
new Date(d.getFullYear(), d.getMonth() + 1, 0);

获取日期的月份名称
#

// `date` is a Date object
const getMonthName = (date) =>
[
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
" November",
"December",
][date.getMonth()];

获取给定月份的天数
#

// `month` is zero-based index
const daysInMonth = (month, year) => new Date(year, month, 0).getDate();

获取时区字符串
#

const getTimezone = () => Intl.DateTimeFormat().resolvedOptions().timeZone;

// Example
getTimezone(); // 'Asia/Saigon'

获取明天的日期
#

const tomorrow = ((d) => new Date(d.setDate(d.getDate() + 1)))(new Date());

// Or
const tomorrow = new Date(new Date().valueOf() + 1000 * 60 * 60 * 24);

获取一年中的总天数
#

const numberOfDays = (year) =>
(year % 4 === 0 && year % 100 !== 0) || year % 400 === 0 ? 366 : 365;

// Or
const numberOfDays = (year) =>
new Date(year, 1, 29).getDate() === 29 ? 366 : 365;

获取日期的工作日
#

// `date` is a Date object
const getWeekday = (date) =>
[
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
][date.getDay()];

获取昨天的日期
#

const yesterday = ((d) => new Date(d.setDate(d.getDate() - 1)))(new Date());

// Or
const yesterday = new Date(new Date().valueOf() - 1000 * 60 * 60 * 24);

初始化当前日期,但将时间设置为午夜
#

const midnightOfToday = () => new Date(new Date().setHours(0, 0, 0, 0));

排序日期数组
#

// `arr` is an array of `Date` items
const sortDescending = (arr) => arr.sort((a, b) => a.getTime() > b.getTime());
const sortAscending = (arr) => arr.sort((a, b) => a.getTime() < b.getTime());
Function

Box handler
#

const boxHandler = x => ({ next: f => boxHandler(f(x)), done: f => f(x) });

// Example 1
const getPercentNumber = str => boxHandler(str).next(str => str.replace(/\%/, '')).next(str => parseFloat(str)).done(res => res * 0.01);

getPercentNumber('50%'); // 0.5

// Example 2
const getMoney = (price) => Number.parseFloat(price.replace(/\$/, ''));
const getPercent = (percent) => Number.parseFloat(percent.replace(/\%/)) * 0.01;

const getDiscountPrice = (price, discount) => boxHandler(getMoney(price)).done(cents => boxHandler(getPercent(discount)).next(save => cents - (cents * save))).done(res => res);

getDiscountPrice('$6.00', '20%'); // 4.8

检查值是否为函数
#

const isFunction = (v) =>
[
"[object Function]",
"[object GeneratorFunction]",
"[object AsyncFunction]",
"[object Promise]",
].includes(Object.prototype.toString.call(v));

// Examples
isFunction(function () {}); // true
isFunction(function* () {}); // true
isFunction(async function () {}); // true

检查值是否是生成器函数
#

const isGeneratorFunction = (v) =>
Object.prototype.toString.call(v) === "[object GeneratorFunction]";

// Examples
isGeneratorFunction(function () {}); // false
isGeneratorFunction(function* () {}); // true

检查值是否是异步函数
#

const isAsyncFunction = (v) =>
Object.prototype.toString.call(v) === "[object AsyncFunction]";

// Examples
isAsyncFunction(function () {}); // false
isAsyncFunction(function* () {}); // false
isAsyncFunction(async function () {}); // true

从左到右编写功能
#

// Compose functions from left to right
const pipe =
(...fns) =>
(x) =>
fns.reduce((y, f) => f(y), x);

// Example
const lowercase = (str) => str.toLowerCase();
const capitalize = (str) => `${str.charAt(0).toUpperCase()}${str.slice(1)}`;
const reverse = (str) => str.split("").reverse().join("");

const fn = pipe(lowercase, capitalize, reverse);

// We will execute `lowercase`, `capitalize` and `reverse` in order
fn("Hello World") === "dlrow olleH";

组合功能
#

// Compose functions from right to left
const compose =
(...fns) =>
(x) =>
fns.reduceRight((y, f) => f(y), x);

// Example
const lowercase = (str) => str.toLowerCase();
const capitalize = (str) => `${str.charAt(0).toUpperCase()}${str.slice(1)}`;
const reverse = (str) => str.split("").reverse().join("");

const fn = compose(reverse, capitalize, lowercase);

// We will execute `lowercase`, `capitalize` and `reverse` in order
fn("Hello World") === "dlrow olleH";

创建一个接受单个参数的函数
#

const unary = (fn) => (arg) => fn(arg);

// Example
["1", "2", "3", "4", "5"].map(unary(parseInt)); // [1, 2, 3, 4, 5]

创建一个空函数
#

const noop = () => {};

// Or
const noop = Function();
// calling Function() might be detected as using eval by some security tools

Curry 的函数
#

const curry = (fn, ...args) =>
fn.length <= args.length ? fn(...args) : curry.bind(null, fn, ...args);

// Example
const sum = (a, b, c) => a + b + c;
curry(sum)(1)(2)(3); // 6
curry(sum)(1, 2, 3); // 6
curry(sum, 1)(2, 3); // 6
curry(sum, 1)(2)(3); // 6
curry(sum, 1, 2)(3); // 6
curry(sum, 1, 2, 3); // 6

延迟函数的计算
#

// returns a new version of `fn` that returns values as lazy evaluable
const thunkfy =
(fn) =>
(...args) =>
() =>
fn(...args);

// Example
const heavyComputation = (x) => doStuff(x);
const unnecessarySlow = manyThings
.map(heavyComputation)
.find((result) => result.criteria);
const probablyFaster = manyThings
.map(thunkfy(heavyComputation))
.find((thunk) => thunk().criteria);

一次执行一个函数
#

const once = (fn) =>
(
(ran = false) =>
() =>
ran ? fn : ((ran = !ran), (fn = fn()))
)();

// Example
let n = 0;
const incOnce = once(() => ++n);
incOnce(); // n = 1
incOnce(); // n = 1
incOnce(); // n = 1

翻转函数的参数
#

// Reverse the order of arguments
const flip =
(fn) =>
(...args) =>
fn(...args.reverse());

// For binary functions
const flip = (fn) => (b, a) => fn(a, b);

// Or for curried functions
const flip = (fn) => (b) => (a) => fn(a)(b);

// Example
const isParent = (parent, child) => parent.children.includes(child);
const isChild = flip(isParent);

一致函数
#

const identity = (x) => x;

逻辑异或运算符
#

// returns `true` if one of the arguments is truthy and the other is falsy

const xor = (a, b) => (a && !b) || (!a && b);

// Or
const xor = (a, b) => !(!a && !b) && !(a && b);

// Or
const xor = (a, b) => Boolean(!a ^ !b);

// Examples
xor(true, true); // false
xor(false, false); // false
xor(true, false); // true
xor(false, true); // true

Memoize的一个函数
#

const memoize = (fn) =>
(
(cache = {}) =>
(arg) =>
cache[arg] || (cache[arg] = fn(arg))
)();

// Example
// Calculate Fibonacci numbers
const fibo = memoize((n) => (n <= 2 ? 1 : fibo(n - 1) + fibo(n - 2)));

fibo(1); // 1
fibo(2); // 1
fibo(3); // 2
fibo(4); // 3
fibo(5); // 5
fibo(6); // 8

部分应用函数
#

const partial =
(fn, ...a) =>
(...b) =>
fn(...a, ...b);

// Example
const sum = (x, y) => x + y;
const inc = partial(sum, 1);
inc(9); // 10

Uncurry函数
#

// `fn` is a curried function
// `n` is the depth of parameters
const uncurry =
(fn, n = 1) =>
(...args) =>
(
(acc) => (args) =>
args.reduce((x, y) => x(y), acc)
)(fn)(args.slice(0, n));

// Example
const sum = (a) => (b) => (c) => a + b + c;
uncurry(sum, 1)(1)(2)(3); // 6
uncurry(sum, 2)(1, 2)(3); // 6
uncurry(sum, 3)(1, 2, 3); // 6
Math

计算由两个点定义的直线的角度
#

// In radians
const radiansAngle = (p1, p2) => Math.atan2(p2.y - p1.y, p2.x - p1.x);

// In degrees
const degreesAngle = (p1, p2) =>
(Math.atan2(p2.y - p1.y, p2.x - p1.x) * 180) / Math.PI;

计算两点之间的距离
#

const distance = (p1, p2) =>
Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));

计算两点之间的中点
#

const midpoint = (p1, p2) => [(p1.x + p2.x) / 2, (p1.y + p2.y) / 2];

检查点是否在矩形内
#

const isInside = (point, rect) =>
point.x > rect.left &&
point.x < rect.right &&
point.y > rect.top &&
point.y < rect.bottom;

检查矩形是否包含其他矩形
#

// Returns true if `a` contains `b`
// (x1, y1) and (x2, y2) are top-left and bottom-right corners
const contains = (a, b) =>
a.x1 <= b.x1 && a.y1 <= b.y1 && a.x2 >= b.x2 && a.y2 >= b.y2;

检查矩形是否与另一个矩形重叠
#

// Returns true if `a` overlaps `b`
// (x1, y1) and (x2, y2) are top-left and bottom-right corners
const overlaps = (a, b) =>
(a.x1 < b.x2 && b.x1 < a.x2) || (a.y1 < b.y2 && b.y1 < a.y2);

将角度转换为弧度
#

const degsToRads = (deg) => (deg * Math.PI) / 180.0;

将弧度转换为角度
#

const radsToDegs = (rad) => (rad * 180) / Math.PI;

将数字四舍五入到一个给定值的最接近的倍数
#

const roundNearest = (value, nearest) => Math.round(value / nearest) * nearest;

// Examples
roundNearest(100, 30); // 90
roundNearest(200, 30); // 210
roundNearest(200, 40); // 200
Misc

检查代码是否在NodeJS中运行
#

const isNode =
typeof process !== "undefined" &&
process.versions != null &&
process.versions.node != null;

检查代码是否在浏览器中运行
#

const isBrowser = typeof window === "object" && typeof document === "object";

清除所有Cookie
#

const clearCookies = document.cookie
.split(";")
.forEach(
(c) =>
(document.cookie = c
.replace(/^ +/, "")
.replace(/=.*/, `=;expires=${new Date().toUTCString()};path=/`))
);

将3位数字的颜色转换为6位数字的颜色
#

const toFullHexColor = (color) =>
`#${(color.startsWith("#") ? color.slice(1) : color)
.split("")
.map((c) => `${c}${c}`)
.join("")}
`
;

// Example
toFullHexColor("123"); // '#112233'
toFullHexColor("#123"); // '#112233'
toFullHexColor("#abc"); // '#aabbcc'

转换摄氏到华氏度
#

const celsiusToFahrenheit = (celsius) => (celsius * 9) / 5 + 32;

// Examples
celsiusToFahrenheit(15); // 59
celsiusToFahrenheit(0); // 32
celsiusToFahrenheit(-20); // -4

转换华氏到摄氏
#

const fahrenheitToCelsius = (fahrenheit) => ((fahrenheit - 32) * 5) / 9;

// Examples
fahrenheitToCelsius(59); // 15
fahrenheitToCelsius(32); // 0

将十六进制转换为RGB
#

const hexToRgb = (hex) =>
hex
.replace(
/^#?([a-f\d])([a-f\d])([a-f\d])$/i,
(_, r, g, b) => `#${r}${r}${g}${g}${b}${b}`
)
.substring(1)
.match(/.{2}/g)
.map((x) => parseInt(x, 16));

// Examples
hexToRgb("#00ffff"); // [0, 255, 255]
hexToRgb("#0ff"); // [0, 255, 255]

将RGB颜色转换为十六进制
#

const rgbToHex = (red, green, blue) =>
`#${((1 << 24) + (red << 16) + (green << 8) + blue).toString(16).slice(1)}`;

// Or
const rgbToHex = (red, green, blue) =>
`#${[red, green, blue].map((v) => v.toString(16).padStart(2, "0")).join("")}`;

// Example
rgbToHex(0, 255, 255); // '#00ffff'

将URL参数转换为对象
#

const getUrlParams = (query) =>
Array.from(new URLSearchParams(query)).reduce(
(p, [k, v]) =>
Object.assign({}, p, {
[k]: p[k] ? (Array.isArray(p[k]) ? p[k] : [p[k]]).concat(v) : v,
}),
{}
);

// Examples
getUrlParams(location.search); // Get the parameters of the current URL

getUrlParams("foo=Foo&bar=Bar"); // { foo: "Foo", bar: "Bar" }

// Duplicate key
getUrlParams("foo=Foo&foo=Fuzz&bar=Bar"); // { foo: ["Foo", "Fuzz"], bar: "Bar" }

解码JWT令牌
#

const decode = (token) =>
decodeURIComponent(
atob(token.split(".")[1].replace("-", "+").replace("_", "/"))
.split("")
.map((c) => `%${("00" + c.charCodeAt(0).toString(16)).slice(-2)}`)
.join("")
);

// Example
decode(`
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0I
joxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
`
);

// { "sub": "1234567890", "name": "John Doe", "iat": 1516239022 }

检测暗模式
#

const isDarkMode =
window.matchMedia &&
window.matchMedia("(prefers-color-scheme: dark)").matches;

Easing functions
#

// Some easing functions
// See https://gist.github.com/gre/1650294 and https://easings.net

const linear = (t) => t;

const easeInQuad = (t) => t * t;
const easeOutQuad = (t) => t * (2 - t);
const easeInOutQuad = (t) => (t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t);

const easeInCubic = (t) => t * t * t;
const easeOutCubic = (t) => --t * t * t + 1;
const easeInOutCubic = (t) =>
t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;

const easeInQuart = (t) => t * t * t * t;
const easeOutQuart = (t) => 1 - --t * t * t * t;
const easeInOutQuart = (t) =>
t < 0.5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t;

const easeInQuint = (t) => t * t * t * t * t;
const easeOutQuint = (t) => 1 + --t * t * t * t * t;
const easeInOutQuint = (t) =>
t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * --t * t * t * t * t;

const easeInSine = (t) => 1 + Math.sin((Math.PI / 2) * t - Math.PI / 2);
const easeOutSine = (t) => Math.sin((Math.PI / 2) * t);
const easeInOutSine = (t) => (1 + Math.sin(Math.PI * t - Math.PI / 2)) / 2;

const easeInElastic = (t) => (0.04 - 0.04 / t) * Math.sin(25 * t) + 1;
const easeOutElastic = (t) => ((0.04 * t) / --t) * Math.sin(25 * t);
const easeInOutElastic = (t) =>
(t -= 0.5) < 0
? (0.02 + 0.01 / t) * Math.sin(50 * t)
: (0.02 - 0.01 / t) * Math.sin(50 * t) + 1;

模拟掷骰子
#

const throwdice = () => ~~(Math.random() * 6) + 1;

// Examples
throwdice(); // 4
throwdice(); // 1
throwdice(); // 6

编码网址
#

// `encodeURIComponent` doesn't encode -_.!~*'()
const encode = (url) =>
encodeURIComponent(url)
.replace(/!/g, "%21")
.replace(/~/g, "%7E")
.replace(/\*/g, "%2A")
.replace(/'/g, "%27")
.replace(/\(/g, "%28")
.replace(/\)/g, "%29")
.replace(/%20/g, "+");

生成唯一的增量ID
#

const uid = (() => ((id = 0), () => id++))();

// Examples
uid(); // 0
uid(); // 1
uid(); // 2
uid(); // 3

获取第一个已定义且非null的参数
#

const coalesce = (...args) =>
args.find((item) => item !== undefined && item !== null);

// Or
const coalesce = (...args) =>
args.find((item) => ![undefined, null].includes(item));

// Examples
coalesce(undefined, null, "helloworld", NaN); // 'helloworld'

从URL获取参数的值
#

const getParam = (url, param) =>
new URLSearchParams(new URL(url).search).get(param);

// Example
getParam("http://domain.com?message=hello", "message"); // 'hello'

获取字符串中变量的类型
#

const getTypeOf = (obj) =>
Object.prototype.toString.call(obj).match(/\[object (.*)\]/)[1];

// Examples
getTypeOf("hello world"); // String
getTypeOf(1000); // Number
getTypeOf(Infinity); // Number
getTypeOf(true); // Boolean
getTypeOf(Symbol()); // Symbol
getTypeOf(null); // Null
getTypeOf(undefined); // Undefined
getTypeOf({}); // Object
getTypeOf([]); // Array
getTypeOf(/[a-z]/g); // RegExp
getTypeOf(new Date(2021)); // Date
getTypeOf(new Error()); // Error
getTypeOf(function () {}); // Function
getTypeOf((a, b) => a + b); // Function
getTypeOf(async () => {}); // AsyncFunction
getTypeOf(document); // HTMLDocument

如果页面位于HTTP中,则将其重定向到HTTPS
#

const redirectHttps = () =>
location.protocol === "https:"
? {}
: location.replace(`https://${location.href.split("//")[1]}`);

// Or
const redirectHttps = () =>
location.protocol === "https:" ? {} : (location.protocol = "https:");

按顺序运行Promises
#

// `promises` is an array of `Promise`
const run = (promises) =>
promises.reduce(
(p, c) => p.then((rp) => c.then((rc) => [...rp, rc])),
Promise.resolve([])
);

// Example
run(promises).then((results) => {
// `results` is an array of promise results in the same order
});

交换两个变量
#

[a, b] = [b, a];

// Or
a = [b, (b = a)][0];

// Or
a = ((x) => x)(b, (b = a));

// Or
// (only works with numbers)
a = b + ((b = a), 0);

a = b * ((b = a), 1);

等待一段时间
#

const wait = async (milliseconds) =>
new Promise((resolve) => setTimeout(resolve, milliseconds));
Number

在数字后添加序数后缀
#

// `n` is a position number
const addOrdinal = (n) =>
`${n}${["st", "nd", "rd"][((((n + 90) % 100) - 10) % 10) - 1] || "th"}`;

// Or
const addOrdinal = (n) => `${n}${[, "st", "nd", "rd"][/1?.$/.exec(n)] || "th"}`;

// Or
const addOrdinal = (n) =>
`${n}${[, "st", "nd", "rd"][(n % 100 >> 3) ^ 1 && n % 10] || "th"}`;

// Or
const addOrdinal = (n) =>
`${n}${
{ one: "st", two: "nd", few: "rd", other: "th" }[
new Intl.PluralRules("en", { type: "ordinal" }).select(n)
]
}
`
;

// Examples
addOrdinal(1); // '1st'
addOrdinal(2); // '2nd'
addOrdinal(3); // '3rd'
addOrdinal(11); // '11th'
addOrdinal(12); // '13th'
addOrdinal(13); // '13th'

计算斐波那契数
#

const fibo = (n, memo = {}) =>
memo[n] || (n <= 2 ? 1 : (memo[n] = fibo(n - 1, memo) + fibo(n - 2, memo)));

// Examples
fibo(1); // 1
fibo(2); // 1
fibo(3); // 2
fibo(4); // 3
fibo(5); // 5
fibo(6); // 8

计算参数的平均值
#

const average = (...args) => args.reduce((a, b) => a + b) / args.length;

// Example
average(1, 2, 3, 4); // 2.5

计算参数除法
#

const division = (...args) => args.reduce((a, b) => a / b);

// Example
division(1, 2, 3, 4); // 0.04166666666666666

计算数字的阶乘
#

const factorial = (n) => (n <= 1 ? 1 : n * factorial(n - 1));

// Examples
factorial(2); // 2
factorial(3); // 6
factorial(4); // 24
factorial(5); // 120
factorial(6); // 720

计算集合索引的mod
#

const mod = (a, b) => ((a % b) + b) % b;

// Examples
mod(-1, 5); // 4
mod(3, 5); // 3
mod(6, 5); // 1

计算参数除法的余数
#

const remainder = (...args) => args.reduce((a, b) => a % b);

// Example
remainder(1, 2, 3, 4); // 1

计算参数之和
#

const sum = (...args) => args.reduce((a, b) => a + b);

// Example
sum(1, 2, 3, 4); // 10

将一个数字夹在两个值之间
#

const clamp = (val, min = 0, max = 1) => Math.max(min, Math.min(max, val));

// Example
clamp(199, 10, 25); // 25

计算两个数字之间的最大公约数
#

const gcd = (a, b) => (b === 0 ? a : gcd(b, a % b));

// Example
gcd(10, 15); // 5

将数字转换为等效字符
#

const toChars = (n) =>
`${n >= 26 ? toChars(Math.floor(n / 26) - 1) : ""}${
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"[n % 26]
}
`
;

// Examples
toChars(0); // A
toChars(1); // B
toChars(25); // Z

toChars(26); // AA
toChars(27); // AB
toChars(51); // AZ

toChars(701); // ZZ
toChars(702); // AAA
toChars(703); // AAB

将字符串转换为数字
#

const toNumber = (str) => +str;

// Example
toNumber("42"); // 42

将十进制递归转换为二进制
#

const decToBi = (num) =>
num === 0 ? 0 : (num % 2) + 10 * decToBi(~~(num / 2));

// Example
decToBi(10); //1010

从数字中获取数字数组
#

const digitize = (n) => `${n}`.split("").map((v) => parseInt(v, 10));

// Or
const digitize = (n) => [...`${n}`].map((v) => parseInt(v, 10));

// Example
digitize(123); // [1, 2, 3]

相乘参数
#

const mul = (...args) => args.reduce((a, b) => a * b);

// Example
mul(1, 2, 3, 4); // 24

前缀为零的整数
#

const prefixWithZeros = (number, length) =>
(number / Math.pow(10, length)).toFixed(length).substr(2);

// Or
const prefixWithZeros = (number, length) =>
`${Array(length).join("0")}${number}`.slice(-length);

// Or
const prefixWithZeros = (number, length) =>
String(number).padStart(length, "0");

// Example
prefixWithZeros(42, 5); // '00042'

将数字四舍五入到给定的数字
#

const round = (n, decimals = 0) =>
Number(`${Math.round(`${n}e${decimals}`)}e-${decimals}`);

// Examples
round(1.234567, 3); // 1.235
round(1.234567, 4); // 1.2346

减去参数
#

const subtract = (...args) => args.reduce((a, b) => a - b);

// Example
subtract(1, 2, 3, 4); // -8

将数字截断为十进制
#

const truncate = (n) => ~~n;

// Examples
truncate(25.198726354); // 25
truncate(-25.198726354); // -25

将数字截断到给定的小数位数而不四舍五入
#

const toFixed = (n, fixed) =>
`${n}`.match(new RegExp(`^-?\\d+(?:\.\\d{0,${fixed}})?`))[0];

// Or
const toFixed = (n, fixed) => ~~(Math.pow(10, fixed) * n) / Math.pow(10, fixed);

// Examples
toFixed(25.198726354, 1); // 25.1
toFixed(25.198726354, 2); // 25.19
toFixed(25.198726354, 3); // 25.198
toFixed(25.198726354, 4); // 25.1987
toFixed(25.198726354, 5); // 25.19872
toFixed(25.198726354, 6); // 25.198726
Object

检查多个对象是否相等
#

const isEqual = (...objects) =>
objects.every((obj) => JSON.stringify(obj) === JSON.stringify(objects[0]));

// Examples
isEqual({ foo: "bar" }, { foo: "bar" }); // true
isEqual({ foo: "bar" }, { bar: "foo" }); // false

创建一个没有属性的空映射
#

// `map` doesn't have any properties
const map = Object.create(null);

// The following `map` has `__proto__` property
// const map = {};

根据键和值对创建一个对象
#

const toObj = (arr) => Object.fromEntries(arr);

// Or
const toObj = (arr) => arr.reduce((a, c) => ((a[c[0]] = c[1]), a), {});

// Example
toObj([
["a", 1],
["b", 2],
["c", 3],
]); // { a: 1, b: 2, c: 3 }

从对象数组中提取属性值
#

const pluck = (objs, property) => objs.map((obj) => obj[property]);

// Example
pluck(
[
{ name: "John", age: 20 },
{ name: "Smith", age: 25 },
{ name: "Peter", age: 30 },
],
"name"
); // ['John', 'Smith', 'Peter']

获取对象给定路径的值
#

const getValue = (path, obj) =>
path.split(".").reduce((acc, c) => acc && acc[c], obj);

// Example
getValue("a.b", { a: { b: "Hello World" } }); // 'Hello World';

不可更改地重命名对象键
#

const renameKeys = (keysMap, obj) =>
Object.keys(obj).reduce(
(acc, key) => ({ ...acc, ...{ [keysMap[key] || key]: obj[key] } }),
{}
);

// Examples
const obj = { a: 1, b: 2, c: 3 };
const keysMap = { a: "d", b: "e", c: "f" };
renameKeys(keysMap, obj); // { d: 1, e: 2, f: 3 }

反转对象的键和值
#

const invert = (obj) =>
Object.keys(obj).reduce((res, k) => Object.assign(res, { [obj[k]]: k }), {});

// Or
const invert = (obj) =>
Object.fromEntries(Object.entries(obj).map(([k, v]) => [v, k]));

// Example
invert({ a: "1", b: "2", c: "3" }); // { 1: 'a', 2: 'b', 3: 'c' }

忽略对象的属性子集
#

const omit = (obj, keys) =>
Object.keys(obj)
.filter((k) => !keys.includes(k))
.reduce((res, k) => Object.assign(res, { [k]: obj[k] }), {});

// Example
omit({ a: "1", b: "2", c: "3" }, ["a", "b"]); // { c: '3' }

选择一个对象的属性子集
#

const pick = (obj, keys) =>
Object.keys(obj)
.filter((k) => keys.includes(k))
.reduce((res, k) => Object.assign(res, { [k]: obj[k] }), {});

// Example
pick({ a: "1", b: "2", c: "3" }, ["a", "b"]); // { a: '1', b: '2' }

从对象中删除所有null和未定义的属性
#

const removeNullUndefined = (obj) =>
Object.entries(obj).reduce(
(a, [k, v]) => (v == null ? a : ((a[k] = v), a)),
{}
);

// Or
const removeNullUndefined = (obj) =>
Object.entries(obj)
.filter(([_, v]) => v != null)
.reduce((acc, [k, v]) => ({ ...acc, [k]: v }), {});

// Or
const removeNullUndefined = (obj) =>
Object.fromEntries(Object.entries(obj).filter(([_, v]) => v != null));

// Example
removeNullUndefined({
foo: null,
bar: undefined,
fuzz: 42,
}); // { fuzz: 42 }

浅复制一个对象
#

const shallowCopy = obj => Object.assign({}, obj);

// or
const shallowCopy = obj => {...obj};

按对象的属性对对象进行排序
#

const sort = (obj) =>
Object.keys(obj)
.sort()
.reduce((p, c) => ((p[c] = obj[c]), p), {});

// Example
const colors = {
white: "#ffffff",
black: "#000000",
red: "#ff0000",
green: "#008000",
blue: "#0000ff",
};
sort(colors);
/*
{
black: '#000000',
blue: '#0000ff',
green: '#008000',
red: '#ff0000',
white: '#ffffff',
}
*/
Random

产生一个随机的布尔值
#

const randomBoolean = () => Math.random() >= 0.5;

生成给定范围内的随机浮点数
#

const randomFloat = (min, max) => Math.random() * (max - min) + min;

生成随机的十六进制颜色
#

const randomColor = () =>
`#${Math.random().toString(16).slice(2, 8).padEnd(6, "0")}`;

// Or
const randomColor = () => `#${(~~(Math.random() * (1 << 24))).toString(16)}`;

生成给定范围内的随机整数
#

const randomInteger = (min, max) =>
Math.floor(Math.random() * (max - min + 1)) + min;

生成一个随机IP地址
#

const randomIp = () =>
Array(4)
.fill(0)
.map((_, i) => Math.floor(Math.random() * 255) + (i === 0 ? 1 : 0))
.join(".");

// Example
randomIp(); // 175.89.174.131

产生随机信号
#

const randomSign = () => (Math.random() >= 0.5 ? 1 : -1);

从给定字符生成随机字符串
#

const generateString = (length, chars) =>
Array(length)
.fill("")
.map((v) => chars[Math.floor(Math.random() * chars.length)])
.join("");

// Example
generateString(
10,
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
);

使用Node crypto模块生成随机字符串
#

const randomStr = () => require("crypto").randomBytes(32).toString("hex");

生成给定长度的随机字符串
#

const generateString = (length) =>
Array(length)
.fill("")
.map((v) => Math.random().toString(36).charAt(2))
.join("");

产生随机的UUID
#

const uuid = (a) =>
a
? (a ^ ((Math.random() * 16) >> (a / 4))).toString(16)
: ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, uuid);

生成给定范围内的随机整数数组
#

const randomArrayInRange = (min, max, n) =>
Array.from(
{ length: n },
() => Math.floor(Math.random() * (max - min + 1)) + min
);

// Example
randomArrayInRange(1, 100, 10); // [11, 82, 41, 35, 76, 83, 43, 15, 60, 54]

获取随机项目并将其从数组中删除
#

const randomItem = (arr) => arr.splice((Math.random() * arr.length) | 0, 1);

// Example
const arr = [1, 3, 5, 7, 9];
randomItem(arr); // 7
// arr = [1, 3, 5, 9]

从数组中获取随机项
#

const randomItem = (arr) => arr[(Math.random() * arr.length) | 0];

获取数组的随机项
#

const randomItems = (arr, count) =>
arr
.concat()
.reduce(
(p, _, __, arr) =>
p[0] < count
? [
p[0] + 1,
p[1].concat(arr.splice((Math.random() * arr.length) | 0, 1)),
]
: p,
[0, []]
)[1];

// Examples
randomItems([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 3); // [4, 8, 5]
randomItems(["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"], 4); // ['e', 'c', 'h', 'j']

选择一个对象的随机属性
#

const randomProp = (obj) =>
Object.keys(obj)[(Math.random() * Object.keys(obj).length) | 0];

// Example
const colors = {
aqua: "#00ffff",
azure: "#f0ffff",
beige: "#f5f5dc",
black: "#000000",
blue: "#0000ff",
brown: "#a52a2a",
cyan: "#00ffff",
darkblue: "#00008b",
darkcyan: "#008b8b",
darkgrey: "#a9a9a9",
darkgreen: "#006400",
darkkhaki: "#bdb76b",
darkmagenta: "#8b008b",
darkolivegreen: "#556b2f",
darkorange: "#ff8c00",
darkorchid: "#9932cc",
darkred: "#8b0000",
darksalmon: "#e9967a",
darkviolet: "#9400d3",
fuchsia: "#ff00ff",
gold: "#ffd700",
green: "#008000",
indigo: "#4b0082",
khaki: "#f0e68c",
lightblue: "#add8e6",
lightcyan: "#e0ffff",
lightgreen: "#90ee90",
lightgrey: "#d3d3d3",
lightpink: "#ffb6c1",
lightyellow: "#ffffe0",
lime: "#00ff00",
magenta: "#ff00ff",
maroon: "#800000",
navy: "#000080",
olive: "#808000",
orange: "#ffa500",
pink: "#ffc0cb",
purple: "#800080",
violet: "#800080",
red: "#ff0000",
silver: "#c0c0c0",
white: "#ffffff",
yellow: "#ffff00",
};
randomProp(colors); // 'red'
String

首字符串大写
#

const capitalize = (str) => `${str.charAt(0).toUpperCase()}${str.slice(1)}`;

// Or
const capitalize = ([first, ...rest]) =>
`${first.toUpperCase()}${rest.join("")}`;

// Example
capitalize("hello world"); // 'Hello world'

检查路径是否相对
#

const isRelative = (path) => !/^([a-z]+:)?[\\/]/i.test(path);

// Examples
isRelative("/foo/bar/baz"); // false
isRelative("C:\\foo\\bar\\baz"); // false
isRelative("foo/bar/baz.txt"); // true
isRelative("foo.md"); // true

检查字符串是否包含重复的字符序列
#

const consistsRepeatedSubstring = (str) =>
`${str}${str}`.indexOf(str, 1) !== str.length;

// Example
consistsRepeatedSubstring("aa"); // true
consistsRepeatedSubstring("aaa"); // true
consistsRepeatedSubstring("ababab"); // true
consistsRepeatedSubstring("abc"); // false

检查字符串是否是回文
#

const isPalindrome = (str) => str === str.split("").reverse().join("");

// Examples
isPalindrome("abc"); // false
isPalindrom("abcba"); // true

检查URL是否是绝对的
#

const isAbsoluteUrl = (url) => /^[a-z][a-z0-9+.-]*:/.test(url);

// Example
isAbsoluteUrl("https://1loc.dev"); // true
isAbsoluteUrl("https://1loc.dev/foo/bar"); // true
isAbsoluteUrl("1loc.dev"); // false
isAbsoluteUrl("//1loc.dev"); // false

检查两个字符串是否拼字
#

const areAnagram = (str1, str2) =>
str1.toLowerCase().split("").sort().join("") ===
str2.toLowerCase().split("").sort().join("");

// Examples
areAnagram("listen", "silent"); // true
areAnagram("they see", "the eyes"); // true
areAnagram("node", "deno"); // true

将一个字母转换为关联的表情符号
#

const letterToEmoji = (c) =>
String.fromCodePoint(c.toLowerCase().charCodeAt() + 127365);

// Examples
letterToEmoji("a"); // 🇦
letterToEmoji("b"); // 🇧

将字符串转换为camelCase
#

const toCamelCase = (str) =>
str.trim().replace(/[-_\s]+(.)?/g, (_, c) => (c ? c.toUpperCase() : ""));

// Examples
toCamelCase("background-color"); // backgroundColor
toCamelCase("-webkit-scrollbar-thumb"); // WebkitScrollbarThumb
toCamelCase("_hello_world"); // HelloWorld
toCamelCase("hello_world"); // helloWorld

将字符串转换为PascalCase
#

const toPascalCase = (str) =>
(str.match(/[a-zA-Z0-9]+/g) || [])
.map((w) => `${w.charAt(0).toUpperCase()}${w.slice(1)}`)
.join("");

// Examples
toPascalCase("hello world"); // 'HelloWorld'
toPascalCase("hello.world"); // 'HelloWorld'
toPascalCase("foo_bar-baz"); // FooBarBaz

将字符串转换为URL段
#

const slugify = (string) =>
string
.toLowerCase()
.replace(/\s+/g, "-")
.replace(/[^\w-]+/g, "");

// Example
slugify("Chapter One: Once upon a time..."); // 'chapter-one-once-upon-a-time'

将Windows文件路径转换为Unix路径
#

const toUnixPath = (path) =>
path.replace(/[\\/]+/g, "/").replace(/^([a-zA-Z]+:|\.\/)/, "");

// Examples
toUnixPath("./foo/bar/baz"); // foo/bar/baz
toUnixPath("C:\\foo\\bar\\baz"); // /foo/bar/baz

将camelCase转换为kebab-case,反之亦然
#

const kebabToCamel = (str) => str.replace(/-./g, (m) => m.toUpperCase()[1]);

const camelToKebab = (str) =>
str.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();

// Examples
kebabToCamel("background-color"); // 'backgroundColor'
camelToKebab("backgroundColor"); // 'background-color'

将snake_case转换为camelCase
#

const snakeToCamel = (str) =>
str.toLowerCase().replace(/(_\w)/g, (m) => m.toUpperCase().substr(1));

// Example
snakeToCamel("HELLO_world"); // 'helloWorld'

将Excel列的名称转换为数字
#

const getIndex = (col) =>
col.split("").reduce((prev, next) => prev * 26 + parseInt(next, 36) - 9, 0);

// Examples
getIndex("A"); // 1
getIndex("B"); // 2
getIndex("C"); // 3
getIndex("Z"); // 26

getIndex("AA"); // 27
getIndex("AB"); // 28
getIndex("AC"); // 29
getIndex("AZ"); // 52

getIndex("AAA"); // 703
getIndex("AAB"); // 704

计算字符串中字符的出现
#

const countOccurrences = (str, char) =>
[...str].reduce((a, v) => (v === char ? a + 1 : a), 0);

// Or
const countOccurrences = (str, char) =>
str.split("").reduce((a, v) => (v === char ? a + 1 : a), 0);

// Or
const countOccurrences = (str, char) =>
[...str].filter((item) => item === char).length;

// Or
const countOccurrences = (str, char) =>
str.split("").filter((item) => item === char).length;

// Examples
countOccurrences("a.b.c.d.e", "."); // 4

字符串去大写
#

const decapitalize = (str) => `${str.charAt(0).toLowerCase()}${str.slice(1)}`;

// Or
const decapitalize = ([first, ...rest]) =>
`${first.toLowerCase()}${rest.join("")}`;

// Example
decapitalize("Hello world"); // 'hello world'

转义HTML特殊字符
#

const escape = (str) =>
str
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/'/g, "&#39;")
.replace(/"/g, "&quot;");

// Or
const escape = (str) =>
str.replace(
/[&<>"']/g,
(m) =>
({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" }[
m
])
);

生成字符串的哈希
#

const hash = (str) =>
str
.split("")
.reduce((prev, curr) => (Math.imul(31, prev) + curr.charCodeAt(0)) | 0, 0);

// Or
const hash = (str) =>
str
.split("")
.reduce((prev, curr) => ((prev << 5) - prev + curr.charCodeAt(0)) | 0, 0);

// Example
hash("hello"); // 99162322

获取不带任何参数的基本URL
#

const baseUrl = (url) =>
url.indexOf("?") === -1 ? url : url.slice(0, url.indexOf("?"));

// Or
// Note that `includes` isn't supported in IE 11
const baseUrl = (url) =>
url.includes("?") ? url.slice(0, url.indexOf("?")) : url;

// Example
baseUrl("https://domain.com/path/sub/path?foo=bar&hello=world"); // 'https://domain.com/path/sub/path'

从文件名获取文件扩展名
#

const ext = (fileName) => fileName.split(".").pop();

从URL获取文件名
#

const fileName = (url) => url.substring(url.lastIndexOf("/") + 1);

// Example
fileName("http://domain.com/path/to/document.pdf"); // 'document.pdf'

获取字符串的长度(以字节为单位)
#

const bytes = (str) => new Blob([str]).size;

// Examples
bytes("hello world"); // 11
bytes("🎉"); // 4

获取字符串中的字符数
#

const characterCount = (str, char) => str.split(char).length - 1;

// Or
const characterCount = (str, char) =>
str.replace(new RegExp(String.raw`[^${char}]`, "g"), "").length;

// Examples
characterCount("192.168.1.1", "."); // 3
characterCount("star wars", "s"); // 2

使字符串的第一个字符小写
#

const lowercaseFirst = (str) => `${str.charAt(0).toLowerCase()}${str.slice(1)}`;

// Example
lowercaseFirst("Hello World"); // 'hello World'

标准化文件路径斜杠
#

const normalizePath = (path) => path.replace(/[\\/]+/g, "/");

// Example
normalizePath("\\foo\\bar\\baz\\"); // /foo/bar/baz/
normalizePath(".//foo//bar///////baz/"); // ./foo/bar/baz/

从字符串中删除空格
#

const removeSpaces = (str) => str.replace(/\s/g, "");

// Example
removeSpaces("hel lo wor ld"); // 'helloworld'

重复一个字符串
#

const repeat = (str, numberOfTimes) => str.repeat(numberOfTimes);

// Or
const repeat = (str, numberOfTimes) => Array(numberOfTimes + 1).join(str);

将所有换行符替换为br元素
#

const nl2br = (str) => str.replace(new RegExp("\r?\n", "g"), "<br>");

// In React
str.split("\n").map((item, index) => (
<React.Fragment key={index}>
{item}
<br />
</React.Fragment>
));

用一个空格替换多个空格
#

// Replace spaces, tabs and new line characters
const replaceSpaces = (str) => str.replace(/\s\s+/g, " ");

// Only replace spaces
const replaceOnlySpaces = (str) => str.replace(/ +/g, " ");

// Example
replaceSpaces("this\n is \ta \rmessage"); // 'this is a message'

将字符串的第一个给定字符数替换为另一个字符
#

const mask = (str, num, mask) =>
`${str}`.slice(num).padStart(`${str}`.length, mask);

// Example
mask(1234567890, 3, "*"); // ***4567890

反转字符串
#

const reverse = (str) => str.split("").reverse().join("");

// Or
const reverse = (str) => [...str].reverse().join("");

// Or
const reverse = (str) =>
str.split("").reduce((rev, char) => `${char}${rev}`, "");

// Or
const reverse = (str) =>
str === "" ? "" : `${reverse(str.substr(1))}${str.charAt(0)}`;

// Example
reverse("hello world"); // 'dlrow olleh'

按字母顺序对字符串的字符进行排序
#

const sort = (str) =>
str
.split("")
.sort((a, b) => a.localeCompare(b))
.join("");

// Example
sort("hello world"); // dehllloorw

从字符串中删除ANSI代码
#

const stripAnsiCodes = (str) =>
str.replace(
/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g,
""
);

// Example
stripAnsiCodes("\u001B[4mcake\u001B[0m"); // 'cake'
stripAnsiCodes(
"\u001B[0m\u001B[4m\u001B[42m\u001B[31mfoo\u001B[39m\u001B[49m\u001B[24mfoo\u001B[0m"
); // 'foofoo'

交换字符串中的字符大小写
#

const swapCase = (str) =>
str
.split("")
.map((c) => (c === c.toLowerCase() ? c.toUpperCase() : c.toLowerCase()))
.join("");

// Example
swapCase("Hello World"); // 'hELLO wORLD'

在字符串的开始和结束处修剪斜杠
#

const trimSlashes = (str) => str.replace(/^\/+|\/+$/g, "");

// Or
const trimSlashes = (str) => str.split("/").filter(Boolean).join("/");

// Example
trimSlashes("//hello/world///"); // hello/world

削减一些字符
#

const trim = (str, char) => str.split(char).filter(Boolean).join();

// Examples
trim("/hello world//", "/"); // hello world
trim('"hello world"', '"'); // hello world
trim(" hello world ", " "); // hello world

从文件名中删除文件扩展名
#

const trimExt = (fileName) =>
fileName.indexOf(".") === -1
? fileName
: fileName.split(".").slice(0, -1).join(".");

// Examples
trimExt("document"); // document
trimExt("document.pdf"); // document
trimExt("document.2020.pdf"); // document.2020

在完整单词处截断字符串
#

const truncate = (str, max, suffix) =>
str.length < max
? str
: `${str.substr(
0,
str.substr(0, max - suffix.length).lastIndexOf(" ")
)}
${suffix}`
;

// Example
truncate("This is a long message", 20, "..."); // 'This is a long...'

取消转义HTML特殊字符
#

const unescape = (str) =>
str
.replace(/&amp;/g, "&")
.replace(/&lt;/g, "<")
.replace(/&gt;/g, ">")
.replace(/�*39;/g, "'")
.replace(/&quot;/g, '"');

将字符串中每个单词的第一个字符大写
#

const uppercaseWords = (str) =>
str
.split(" ")
.map((w) => `${w.charAt(0).toUpperCase()}${w.slice(1)}`)
.join(" ");

// Or
const uppercaseWords = (str) =>
str.replace(/^(.)|\s+(.)/g, (c) => c.toUpperCase());

// Example
uppercaseWords("hello world"); // 'Hello World'
Validator

检查日期是否是工作日
#

// `date` is a Date object
const isWeekday = (date = new Date()) => date.getDay() % 6 !== 0;

检查日期是否是周末
#

// `date` is a Date object
const isWeekend = (date = new Date()) => date.getDay() % 6 === 0;

检查日期是否在两个日期之间
#

// `min`, `max` and `date` are `Date` instances
const isBetween = (date, min, max) =>
date.getTime() >= min.getTime() && date.getTime() <= max.getTime();

检查日期是否是今天
#

// `date` is a Date object
const isToday = (date) =>
date.toISOString().slice(0, 10) === new Date().toISOString().slice(0, 10);

检查日期是否在当年
#

// `date` is a Date object
const isCurrentYear = (date) =>
date.getUTCFullYear() === new Date().getUTCFullYear();

检查平面数组是否有重复值
#

const hasDuplicateValues = (arr) => new Set(arr).size !== arr.length;

// Examples
hasDuplicateValues(["h", "e", "l", "l", "o"]); // true
hasDuplicateValues(["w", "o", "r", "d"]); // false

检查给定的整数是否是质数
#

const isPrime = (num) =>
num > 1 &&
Array(Math.floor(Math.sqrt(num)) - 1)
.fill(0)
.map((_, i) => i + 2)
.every((i) => num % i !== 0);

检查数字是否为2的幂
#

const isPowerOfTwo = (number) => (number & (number - 1)) === 0;

// Examples
isPowerOfTwo(256); // true
isPowerOfTwo(129); // false

检查数字是否为偶数
#

const isEven = (number) => number % 2 === 0;

// Or
const isEven = (number) => (number & 1) === 0;

// Or
const isEven = (number) => !(number & 1);

// Or
const isEven = (number) => Number.isInteger(number / 2);

// Examples
isEven(1); // false
isEven(2); // true

检查数字是否在给定范围内
#

const inRange = (num, a, b, threshold = 0) =>
Math.min(a, b) - threshold <= num && num <= Math.max(a, b) + threshold;

// Example
inRange(10, 5, 15); // true
inRange(10, 5, 6); // false
inRange(10, 15, 5); // true
inRange(-10, -5, -15); // true

检查数字是否为负
#

const isNegative = (number) => Math.sign(number) === -1;

// Or
const isNegative = (number) => number < 0;

// Examples
isNegative(-3); // true
isNegative(8); // false

检查数字是否为奇数
#

const isOdd = (number) => number % 2 !== 0;

// Or
const isOdd = (number) => !!(number & 1);

// Or
const isOdd = (number) => !Number.isInteger(number / 2);

// Examples
isOdd(1); // true
isOdd(2); // false

检查数字是否为正
#

const isPositive = (number) => Math.sign(number) === 1;

// Examples
isPositive(3); // true
isPositive(-8); // false

检查字符串是否包含小写字符
#

const containsLowerCase = (str) => str !== str.toUpperCase();

// Examples
containsLowerCase("Hello World"); // true
containsLowerCase("HELLO WORLD"); // false

检查字符串是否仅包含ASCII字符
#

const isAscii = (str) => /^[\x00-\x7F]+$/.test(str);

检查字符串是否仅包含数字
#

const isNumeric = (str) => !/[^0-9]/.test(str);

// Examples
isNumeric(2); // true
isNumeric("23"); // true
isNumeric("00123"); // true

isNumeric("1.23"); // false
isNumeric("-Infinity"); // false
isNumeric("Infinity"); // false
isNumeric("NaN"); // false

检查字符串是否仅包含字母和数字
#

const isAlphanumeric = (str) => /^[0-9A-Z]+$/i.test(str);

// Examples
isAlphanumeric("helloworld"); // true
isAlphanumeric("HelloWorld"); // true
isAlphanumeric("hello world"); // false
isAlphanumeric("hello123"); // true
isAlphanumeric("hello 123"); // false

检查字符串是否仅包含字母
#

const isAlpha = (str) => /^[A-Z]+$/i.test(str);

// Examples
isAlpha("helloworld"); // true
isAlpha("HelloWorld"); // true
isAlpha("hello world"); // false
isAlpha("0123456789"); // false

检查字符串是否包含大写字符
#

const containsUpperCase = (str) => str !== str.toLowerCase();

// Examples
containsUpperCase("Hello World"); // true
containsUpperCase("hello world"); // false

检查字符串是否包含空格
#

const containsWhitespace = (str) => (str) => /\s/.test(str);

// Example
containsWhitespace("hello world"); // true

检查字符串是否为十六进制颜色
#

const isHexColor = (color) =>
/^#([0-9A-F]{3}|[0-9A-F]{4}|[0-9A-F]{6}|[0-9A-F]{8})$/i.test(color);

// Examples
isHexColor("#012"); // true
isHexColor("#A1B2C3"); // true
isHexColor("012"); // false
isHexColor("#GHIJKL"); // false

检查字符串是否为十六进制数字
#

const isHexadecimal = (str) => /^[A-F0-9]+$/i.test(str);

// Or
const isHexadecimal = (str) =>
str.split("").every((c) => "0123456789ABCDEFabcdef".indexOf(c) !== -1);

// Examples
isHexadecimal("123"); // true
isHexadecimal("A1B2C3"); // true
isHexadecimal("#123"); // false

检查字符串是否为MongoDB ObjectId
#

const isMongoId = (str) => str.length === 24 && /^[A-F0-9]+$/i.test(str);

// Or
const isMongoId = (str) =>
str.length === 24 &&
str.split("").every((c) => "0123456789ABCDEFabcdef".indexOf(c) !== -1);

检查字符串是否为八进制数字
#

const isOctal = (str) => /^(0o)?[0-7]+$/i.test(str);

检查字符串是否为小写
#

const isLowerCase = (str) => str === str.toLowerCase();

检查字符串是否为大写
#

const isUpperCase = (str) => str === str.toUpperCase();

检查值是否是业务标识符代码
#

const isBIC = (value) =>
/^[a-zA-Z]{6}[a-zA-Z0-9]{2}([a-zA-Z0-9]{3})?$/.test(value);

检查值是否为数字
#

const isNumber = (value) => !isNaN(parseFloat(value)) && isFinite(value);

检查值是否为普通对象
#

const isPlainObject = (v) =>
!!v &&
typeof v === "object" &&
(v.__proto__ === null || v.__proto__ === Object.prototype);

// Examples
isPlainObject(null); // false
isPlainObject("hello world"); // false
isPlainObject([]); // false
isPlainObject(Object.create(null)); // false
isPlainObject(function () {}); // false

isPlainObject({}); // true
isPlainObject({ a: "1", b: "2" }); // true

检查值是否为正则表达式
#

const isRegExp = (value) =>
Object.prototype.toString.call(value) === "[object RegExp]";

检查值是否为字符串
#

const isString = (value) =>
Object.prototype.toString.call(value) === "[object String]";

// Examples
isString("hello world"); // true
isString(new String("hello world")); // true
isString(10); // false

检查值是否是对象
#

const isObject = (v) => v !== null && typeof v === "object";

// Examples
isObject(null); // false
isObject("hello world"); // false

isObject({}); // true
isObject([]); // true

检查值是否为base32编码
#

const isBase32 = (value) =>
value.length % 8 === 0 && /^[A-Z2-7]+=*$/.test(value);

检查值是否为base58编码
#

// It doesn't accept the I, O, l characters
const isBase58 = (value) => /^[A-HJ-NP-Za-km-z1-9]*$/.test(value);

检查值是否为base64编码
#

const isBase64 = (value) =>
/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$/.test(
value
);

检查值是否为零
#

const isNil = (value) => value == null;

检查一年是否为leap年
#

const isLeapYear = (year) =>
(year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;

// Or
// Get the number of days in February
const isLeapYear = (year) => new Date(year, 1, 29).getDate() === 29;

检查所有数组元素是否等于给定值
#

const isEqual = (arr, value) => arr.every((item) => item === value);

// Or
// Ends earlier for false arrays
const isEqual = (arr, value) => !arr.some((item) => item !== value);

// Examples
isEqual(["foo", "foo"], "foo"); // true
isEqual(["foo", "bar"], "foo"); // false
isEqual(["bar", "bar"], "foo"); // false

检查数组中的所有项是否相等
#

const areEqual = (arr) =>
arr.length > 0 && arr.every((item) => item === arr[0]);

// Or
const areEqual = (arr) => new Set(arr).size === 1;

// Examples
areEqual([1, 2, 3, 4]); // false
areEqual(["hello", "hello", "hello"]); // true

检查数组是否包含与某些条件匹配的值
#

const contains = (arr, criteria) => arr.some((v) => criteria(v));

// Or
const contains = (arr, criteria) => arr.some(criteria);

// Or
const contains = (arr, criteria) => arr.filter(criteria).length > 0;

// Examples
contains([10, 20, 30], (v) => v > 25); // true
contains([10, 20, 30], (v) => v > 100 || v < 15); // true
contains([10, 20, 30], (v) => v > 100); // false

检查数组是否为空
#

const isNotEmpty = (arr) => Array.isArray(arr) && Object.keys(arr).length > 0;

// Examples
isNotEmpty([]); // false
isNotEmpty([1, 2, 3]); // true

检查一个数组是否是其他数组的子集
#

// Check if `b` is subset of `a`
const isSubset = (a, b) => new Set(b).size === new Set(b.concat(a)).size;

// Or
const isSubset = (a, b) => b.join("|").includes(a.join("|"));

// Examples
isSubset([1, 2], [1, 2, 3, 4]); // true
isSubset([1, 2, 5], [1, 2, 3, 4]); // false
isSubset([6], [1, 2, 3, 4]); // false

检查对象是否为Promise
#

const isPromise = (obj) =>
!!obj &&
(typeof obj === "object" || typeof obj === "function") &&
typeof obj.then === "function";

检查对象是否为数组
#

const isArray = (obj) => Array.isArray(obj);

检查对象是否为空
#

const isEmpty = (obj) =>
Reflect.ownKeys(obj).length === 0 && obj.constructor === Object;

// Or for enumerable property names only
const isEmpty = (obj) => JSON.stringify(obj) === "{}";

验证公历日期
#

// `m`: the month (zero-based index)
// `d`: the day
// `y`: the year
const isValidDate = (m, d, y) =>
0 <= m &&
m <= 11 &&
0 < y &&
y < 32768 &&
0 < d &&
d <= new Date(y, m, 0).getDate();