判断各种数据
ts
// cache toString
const toTagString = Object.prototype.toString;
const FuncToString = Function.prototype.toString;
// get value object tag like: [object Array]
export function getObjectTag(value: unknown): string {
return toTagString.call(value);
}
// value is object or not
export function isObject(value: unknown): boolean {
return value !== null && typeof value === "object";
}
// value instance of Object or not
export function isPlainObject(value: unknown): boolean {
return getObjectTag(value) === "[object Object]";
}
// value is number or not
export function isNumber(value: unknown): boolean {
return typeof value === "number";
}
// value is string or not
export function isString(value: unknown): boolean {
return typeof value === "string";
}
// value is undefined or not
export function isUndefind(value: unknown): boolean {
return value === undefined;
}
// value is null or not
export function isNull(value: unknown): boolean {
return value === null;
}
// value is null or undefined
export function isNullable(value: unknown): boolean {
return Boolean(value === null || value === undefined);
}
// value is boolean or not
export function isBoolean(value: unknown): boolean {
return typeof value === "boolean";
}
// value is symbol or not
export function isSymbol(value: unknown): boolean {
return typeof value === "symbol";
}
// value is function or not
export function isFunction(value: unknown): boolean {
return typeof value === "function";
}
export const isCallable = isFunction;
// value is isNative function or not
export function isNativeFunction(func: Function): boolean {
return isFunction(func) && FuncToString.call(func).includes("[native code]");
}
// value is promise like or not
export function isPromise(p: unknown): boolean {
return isObject(p) && isFunction(p.then);
}
// value is ES6 native promise or not
export function isNativePromise(p: unknown): boolean {
return isObject(p) && getObjectTag(p) === "[object Promise]";
}
// value instance of Date or not
export function isDate(value: unknown): boolean {
return getObjectTag(value) === "[object Date]";
}
// value instance of RegExp or not
export function isRegexp(value: unknown): boolean {
return getObjectTag(value) === "[object RegExp]";
}
// isMap & isWeakMap
export function isMap(value: unknown): boolean {
return isObject(value) && getObjectTag(value) === "[object Map]";
}
export function isWeakMap(value: unknown): boolean {
return isObject(value) && getObjectTag(value) === "[object WeakMap]";
}
// isSet & isWeakSet
export function isSet(value: unknown): boolean {
return isObject(value) && getObjectTag(value) === "[object Set]";
}
export function isWeakSet(value: unknown): boolean {
return isObject(value) && getObjectTag(value) === "[object WeakSet]";
}
// value is Element Node or not
export function isElement(value: unknown): boolean {
return isObject(value) && value.nodeType === 1 && !isPlainObject(value);
}
// is errors object, it's includes
// Error EvalError RangeError ReferenceError SyntaxError TypeError URIError
export function isError(value: unknown): boolean {
if (!isObject(value)) {
return false;
}
const tag = getObjectTag(value);
return Boolean(
tag === "[object Error]" ||
tag === "[object DOMException]" ||
(typeof value.message === "string" &&
typeof value.name === "string" &&
!isPlainObject(value))
);
}
// is length property number or not
export function isLength(len: number) {
return len >= 0 && Number.isSafeInteger(len);
}
// isArray / isArrayLike
export const isArray = Array.isArray;
export function isArrayLike<T extends { length: number }>(value: T): boolean {
if (isFunction(value)) {
return false;
}
return isLength(value.length);
}
// value is File | Blob object or not
export function isFile(value: unknown) {
const tag = getObjectTag(value);
return tag === "[object Blob]" || tag === "[object File]";
}
// is empty Array/Object/Set/Map values
export function isEmpty(value: any): boolean {
if (isPlainObject(value)) {
return Object.keys(value).length === 0;
}
if (isString(value) || Array.isArray(value) || isArrayLike(value)) {
return value.length === 0;
}
if (isMap(value) || isSet(value) || isFile(value)) {
return value.size === 0;
}
return false;
}
// is primitive value or not
function isPrimitive(value) {
var primitiveTags = [
"string",
"number",
"boolean",
"undefined",
"bigint",
"symbol",
];
return value === null || primitiveTags.indexOf(typeofstr) !== -1;
}
// isNode
export function isNode() {
return getObjectTag(globalThis) === "[object global]" && isUndefind(window);
}
// isBrowser
export function isBrowser() {
return window && getObjectTag(window) === "[object Window]";
}
js
// cache toString
const toTagString = Object.prototype.toString;
const FuncToString = Function.prototype.toString;
// get value object tag like: [object Array]
export function getObjectTag(value) {
return toTagString.call(value);
}
// value is object or not
export function isObject(value) {
return value !== null && typeof value === "object";
}
// value instance of Object or not
export function isPlainObject(value) {
return getObjectTag(value) === "[object Object]";
}
// value is number or not
export function isNumber(value) {
return typeof value === "number";
}
// value is string or not
export function isString(value) {
return typeof value === "string";
}
// value is undefined or not
export function isUndefind(value) {
return value === undefined;
}
// value is null or not
export function isNull(value) {
return value === null;
}
// value is null or undefined
export function isNullable(value) {
return Boolean(value === null || value === undefined);
}
// value is boolean or not
export function isBoolean(value) {
return typeof value === "boolean";
}
// value is symbol or not
export function isSymbol(value) {
return typeof value === "symbol";
}
// value is function or not
export function isFunction(value) {
return typeof value === "function";
}
export const isCallable = isFunction;
// value is isNative function or not
export function isNativeFunction(func) {
return isFunction(func) && FuncToString.call(func).includes("[native code]");
}
// value is promise like or not
export function isPromise(p) {
return isObject(p) && isFunction(p.then);
}
// value is ES6 native promise or not
export function isNativePromise(p) {
return isObject(p) && getObjectTag(p) === "[object Promise]";
}
// value instance of Date or not
export function isDate(value) {
return getObjectTag(value) === "[object Date]";
}
// value instance of RegExp or not
export function isRegexp(value) {
return getObjectTag(value) === "[object RegExp]";
}
// isMap & isWeakMap
export function isMap(value) {
return isObject(value) && getObjectTag(value) === "[object Map]";
}
export function isWeakMap(value) {
return isObject(value) && getObjectTag(value) === "[object WeakMap]";
}
// isSet & isWeakSet
export function isSet(value) {
return isObject(value) && getObjectTag(value) === "[object Set]";
}
export function isWeakSet(value) {
return isObject(value) && getObjectTag(value) === "[object WeakSet]";
}
// value is Element Node or not
export function isElement(value) {
return isObject(value) && value.nodeType === 1 && !isPlainObject(value);
}
// is errors object, it's includes
// Error EvalError RangeError ReferenceError SyntaxError TypeError URIError
export function isError(value) {
if (!isObject(value)) {
return false;
}
const tag = getObjectTag(value);
return Boolean(
tag === "[object Error]" ||
tag === "[object DOMException]" ||
(typeof value.message === "string" &&
typeof value.name === "string" &&
!isPlainObject(value))
);
}
// is length property number or not
export function isLength(len) {
return len >= 0 && Number.isSafeInteger(len);
}
// isArray / isArrayLike
export const isArray = Array.isArray;
export function isArrayLike(value) {
if (isFunction(value)) {
return false;
}
return isLength(value.length);
}
// value is File | Blob object or not
export function isFile(value) {
const tag = getObjectTag(value);
return tag === "[object Blob]" || tag === "[object File]";
}
// is empty Array/Object/Set/Map values
export function isEmpty(value) {
if (isPlainObject(value)) {
return Object.keys(value).length === 0;
}
if (isString(value) || Array.isArray(value) || isArrayLike(value)) {
return value.length === 0;
}
if (isMap(value) || isSet(value) || isFile(value)) {
return value.size === 0;
}
return false;
}
// is primitive value or not
function isPrimitive(value) {
var primitiveTags = [
"string",
"number",
"boolean",
"undefined",
"bigint",
"symbol",
];
return value === null || primitiveTags.indexOf(typeofstr) !== -1;
}
// isNode
export function isNode() {
return getObjectTag(globalThis) === "[object global]" && isUndefind(window);
}
// isBrowser
export function isBrowser() {
return window && getObjectTag(window) === "[object Window]";
}
字符串格式处理
ts
/**
* 驼峰式字符串
* @param str - 要处理的字符串
* @param firstUpper - 第一个字符是否大写
* @param separators - 分割符号
* @returns 处理后的字符串
*/
export function camelCase(
str: string,
firstUpper: boolean = false,
separators: string[] = ["-", "_"]
): string {
if (str.length < 2) {
return firstUpper ? str : str.toUpperCase();
}
let res = "";
let shouldUpperCase = false;
for (let i = 0, len = str.length; i < len; i++) {
let char = str[i];
if (separators.includes(char)) {
shouldUpperCase = true;
continue;
}
if (shouldUpperCase || (i === 0 && firstUpper)) {
char = char.toUpperCase();
}
res += char;
shouldUpperCase = false;
}
return res;
}
/**
* 根据驼峰式字符串切分新的字符串
* @param str - 要处理的字符串
* @param separator - 切分符号
* @returns 处理完的字符串
*/
function splitCamelCase(str: string, separator: string): string {
if (separator.length > 1) {
separator = separator[0];
}
const isUpperCacse = (char: string) => char === char.toUpperCase();
let char;
let res = "";
for (let i = 0, len = str.length; i < len; i++) {
char = str[i];
if (isUpperCacse(char)) {
if (i > 0) {
res += separator;
}
res += char.toLowerCase();
} else {
res += char;
}
}
return res;
}
// 下划线 snake_case
export const snakeCase = (str: string): string => splitCamelCase(str, "_");
// 中横线 kebab-case
export const kebabCase = (str: string): string => splitCamelCase(str, "-");
数组分页
ts
/**
* Paging Arrays
* @params {array} array
* @params {number} size default 1
* @return {Array<any[]>} result
* @throw TypeError
*/
export function chunk<T>(array: T[], size: number = 1): Array<T[]> {
const chunkSize = size >> 0; // convert to number
const len = array.length;
if (len === 0 || chunkSize === 0) {
return [];
}
if (len <= chunkSize) {
return [array];
}
const pages = Math.ceil(len / chunkSize);
const result: T[][] = new Array(pages);
for (let i = 0; i < pages; i++) {
result[i] = array.slice(i * chunkSize, (i + 1) * chunkSize);
}
return result;
}
js
/**
* Paging Arrays
* @params {array} array
* @params {number} size default 1
* @return {Array<any[]>} result
* @throw TypeError
*/
export function chunk(array, size = 1) {
const chunkSize = size >> 0; // convert to number
const len = array.length;
if (len === 0 || chunkSize === 0) {
return [];
}
if (len <= chunkSize) {
return [array];
}
const pages = Math.ceil(len / chunkSize);
const result = new Array(pages);
for (let i = 0; i < pages; i++) {
result[i] = array.slice(i * chunkSize, (i + 1) * chunkSize);
}
return result;
}
防抖
ts
/**
* 函数防抖
* @param func - 要防止抖动的函数
* @param wait - 触发频率(等待时间)
* @param isImmediate - 第一次是否立即调用
* @param thisArg - 调用函数的时候 this 指向
* @returns
*/
export function debounce(
func: Function,
wait: number = 100,
isImmediate = false,
thisArg?: object
): (...args: any[]) => void {
let timer: NodeJS.Timeout;
let shouldExecute = Boolean(isImmediate);
return function (...args: unknown[]): void {
timer && clearTimeout(timer);
if (shouldExecute) {
func.apply(thisArg, ...args);
shouldExecute = false;
} else {
timer = setTimeout(func.bind(thisArg, ...args), wait);
}
};
}
js
/**
* 函数防抖
* @param func - 要防止抖动的函数
* @param wait - 触发频率(等待时间)
* @param isImmediate - 第一次是否立即调用
* @param thisArg - 调用函数的时候 this 指向
* @returns
*/
export function debounce(
func,
wait = 100,
isImmediate = false,
thisArg = null
) {
let timer;
let shouldExecute = Boolean(isImmediate);
return function (...args) {
timer && clearTimeout(timer);
if (shouldExecute) {
func.apply(thisArg, ...args);
shouldExecute = false;
} else {
timer = setTimeout(func.bind(thisArg, ...args), wait);
}
};
}
节流
ts
export function throttle(
func: Function,
wait: number = 100,
thisArg?: object
): (...args: any[]) => void {
let timer: NodeJS.Timeout;
let startTime = Date.now();
return function (...args: any[]): void {
timer && clearTimeout(timer);
const nowTime = Date.now();
if (startTime + wait >= nowTime) {
func.apply(thisArg, args);
} else {
timer = setTimeout(func.bind(thisArg, ...args), wait);
}
};
}
js
export function throttle(func, wait = 100, thisArg = null) {
let timer;
let startTime = Date.now();
return function (...args) {
timer && clearTimeout(timer);
const nowTime = Date.now();
if (startTime + wait >= nowTime) {
func.apply(thisArg, args);
} else {
timer = setTimeout(func.bind(thisArg, ...args), wait);
}
};
}
柯理化
js
function curry(fn, ...preArgs) {
const countArgs = fn.length;
return function (...args) {
const items = [].concat(...preArgs, ...args);
if (items.length < countArgs) {
return curry.call(this, fn, items);
} else {
return fn.apply(null, items);
}
};
}
遍历对象
ts
/**
* forIn 遍历对象
* @template T extends object - 要遍历的对象
* @template K extends keyof T - 对象所有的 key
* @param obj - 要遍历的对象
* @param callback - 遍历处理函数
* @param onlyOwner - 是否只遍历自身的属性
*/
export function forIn<T extends object, K extends keyof T>(
obj: T,
callback: (key: K, value: T[K], source: T) => void,
onlyOwner: boolean = true
): void {
for (let key in obj) {
if (onlyOwner) {
/* @ts-ignore */
obj.hasOwnProperty(key) && callback(key, obj[key], obj);
} else {
/* @ts-ignore */
callback(key, obj[key], obj);
}
}
}
js
/**
* forIn 遍历对象
* @template T extends object - 要遍历的对象
* @template K extends keyof T - 对象所有的 key
* @param obj - 要遍历的对象
* @param callback - 遍历处理函数
* @param onlyOwner - 是否只遍历自身的属性
*/
export function forIn(obj, callback, onlyOwner = true) {
for (let key in obj) {
if (onlyOwner) {
/* @ts-ignore */
obj.hasownProperty(key) && callback(key, obj[key], obj);
} else {
/* @ts-ignore */
callback(key, obj[key], obj);
}
}
}
格式化日期对象
虽然有很多处理日期的库 moment.js 和 dayjs, 但是最基本的格式化还是得会
ts
/**
* 根据模板字符串格式化日期对象
* @param {Date} date
* @param {string} template
* @returns {string}
*/
export function formatDate(date: Date, template: string): string {
const year = date.getFullYear();
const month = date.getMonth() + 1;
const dates = date.getDate();
const hours = date.getHours();
const minutes = date.getMinutes();
const seconds = date.getSeconds();
const day = date.getDay() + 1;
const fillZero = (value: number): string => {
return value < 10 ? `0${value}` : String(value);
};
const templateMap = {
"{y}": year.toString().slice(-2),
"{Y}": year,
"{m}": month,
"{M}": fillZero(month),
"{d}": dates,
"{D}": fillZero(dates),
"{h}": hours,
"{H}": fillZero(hours),
"{i}": minutes,
"{I}": fillZero(minutes),
"{s}": seconds,
"{S}": fillZero(seconds),
"{w}": day,
};
let formated = template;
const keys = Object.keys(templateMap) as Array<keyof typeof templateMap>;
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const value = String(templateMap[key]);
formated = formated.replace(key, value);
}
return formated;
}
js
/**
* 根据模板字符串格式化日期对象
* @param {Date} date
* @param {string} template
* @returns {string}
*/
export function formatDate(date, template) {
const year = date.getFullYear();
const month = date.getMonth() + 1;
const dates = date.getDate();
const hours = date.getHours();
const minutes = date.getMinutes();
const seconds = date.getSeconds();
const day = date.getDay() + 1;
const fillZero = (value) => {
return value < 10 ? `0${value}` : String(value);
};
const templateMap = {
"{y}": year.toString().slice(-2),
"{Y}": year,
"{m}": month,
"{M}": fillZero(month),
"{d}": dates,
"{D}": fillZero(dates),
"{h}": hours,
"{H}": fillZero(hours),
"{i}": minutes,
"{I}": fillZero(minutes),
"{s}": seconds,
"{S}": fillZero(seconds),
"{w}": day,
};
let formated = template;
const keys = Object.keys(templateMap);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const value = String(templateMap[key]);
formated = formated.replace(key, value);
}
return formated;
}
获取随机字符串/颜色字符串
ts
/**
* get a random string id
* @return {string}
*/
export function randomString(): string {
return Math.random().toString(16).substring(2);
}
/**
* get a random hex color string
* @return {string}
*/
export function getRandomHexColor(): string {
return "#" + Math.floor(Math.random() * 0xffffff).toString(16);
}
js
/**
* get a random string id
* @return {string}
*/
export function randomString() {
return Math.random().toString(16).substring(2);
}
/**
* get a random hex color string
* @return {string}
*/
export function getRandomHexColor() {
return "#" + Math.floor(Math.random() * 0xffffff).toString(16);
}
获取一组数据的平均值
ts
/**
* 获取一组可迭代数据(number类型)的平均值,忽略不是数字的元素
* @param values - 可迭代数据
* @returns number
*/
export function meanOf(values: Iterable<number>): number {
let sum = 0;
let numbersTotal = 0;
for (const item of values) {
if (typeof item !== "number") {
continue;
}
sum += item;
numbersTotal++;
}
return sum / numbersTotal;
}
js
/**
* 获取一组可迭代数据(number类型)的平均值,忽略不是数字的元素
* @param values - 可迭代数据
* @returns number
*/
export function meanOf(values) {
let sum = 0;
let numbersTotal = 0;
for (const item of values) {
if (typeof item !== "number") {
continue;
}
sum += item;
numbersTotal++;
}
return sum / numbersTotal;
}
函数缓存
ts
interface KeyMakerFunc {
(...args: any[]): string;
}
interface MemorizedFunc {
cacheMap: Map<string, unknown>;
(...args: unknown[]): unknown;
}
export function isObject(value: unknown): boolean {
return value !== null && typeof value === "object";
}
const __toStringTag = Object.prototype.toString;
export function getObjectTag(value: unknown): string {
return __toStringTag.call(value);
}
export function isPromise(p: unknown): boolean {
return isObject(p) && getObjectTag(p) === "[object Promise]";
}
/**
* 记忆函数
* @param func - 要缓存接过的函数
* @param keyMaker - 生成缓存 key 的函数
* @returns 返回缓存后的函数
*/
export function useMemorize(
func: CallableFunction,
keyMaker: KeyMakerFunc = JSON.stringify
): MemorizedFunc {
const memorized: MemorizedFunc = (...args: unknown[]) => {
const key = keyMaker({ name: func.name, args });
if (!memorized.cacheMap.has(key)) {
memorized.cacheMap.set(key, func(...args));
}
return memorized.cacheMap.get(key);
};
memorized.cacheMap = new Map();
return memorized;
}
/**
* 异步记忆函数
* @param func - 要缓存接过的函数
* @param keyMaker - 生成缓存 key 的函数
* @returns 返回缓存后的函数
*/
export function useMemorizeAsync(
func: CallableFunction,
keyMaker: KeyMakerFunc = JSON.stringify
): MemorizedFunc {
const memorized: MemorizedFunc = async (...args: unknown[]) => {
const key = keyMaker({ name: func.name, args });
if (!memorized.cacheMap.has(key)) {
const result = func(...args);
if (isPromise(result)) {
const value = await result;
memorized.cacheMap.set(key, value);
} else {
memorized.cacheMap.set(key, result);
}
}
memorized.cacheMap.get(key);
};
memorized.cacheMap = new Map();
return memorized;
}
js
/**
* 函数记忆
* @param func - 要缓存接过的函数
* @param keyMaker - 生成缓存 key 的函数
* @returns 返回缓存后的函数
*/
export function memorize(func, keyMaker = JSON.stringify) {
const memorized = (...args) => {
const key = keyMaker({ name: func.name, args });
if (!memorized.cacheMap.has(key)) {
memorized.cacheMap.set(key, func(...args));
}
return memorized.cacheMap.get(key);
};
memorized.cacheMap = new Map();
return memorized;
}
ts
import { isPromise, useMemorize, useMemorizeAsync } from "@/hooks/useMemorize";
export function delay(cb: CallableFunction, wait: number, ...args: any[]) {
setTimeout(() => cb(...args), wait);
}
export function commitment(isResolved: boolean) {
return new Promise((resolve, reject) => {
if (isResolved) {
resolve("resolved-value");
} else {
reject("rejected-reason");
}
});
}
describe("记忆函数", () => {
it("传入一个函数应该返回一个新的函数", () => {
const fn = vi.fn();
const newFn = useMemorize(fn);
expect(fn).not.toBe(newFn);
});
it("使用相同的参数多次调用应该只调用一次", () => {
const fn = vi.fn();
expect(fn).not.toBeCalled();
const handler = useMemorize(fn);
handler("abc");
handler("abc");
handler("abc");
expect(fn).toBeCalledTimes(1);
handler("def");
handler("def");
handler("def");
expect(fn).toBeCalledTimes(2);
});
it("参数相同, 但是函数名不相同应该不互相影响", () => {
const fn1 = vi.fn();
expect(fn1).not.toBeCalled();
const handler1 = useMemorize(fn1);
handler1("abc");
handler1("abc");
expect(fn1).toBeCalledTimes(1);
const fn2 = vi.fn();
expect(fn2).not.toBeCalled();
const handler2 = useMemorize(fn2);
handler2("abc");
handler2("abc");
expect(fn2).toBeCalledTimes(1);
});
});
describe("异步记忆函数", () => {
it("传入一个函数应该返回一个新的函数, 并且新函数是一个异步函数", () => {
const fn = vi.fn();
const handler = useMemorizeAsync(fn);
expect(fn).not.toBe(handler);
const p = handler();
expect(isPromise(p)).toBe(true);
});
it("传入同步函数, 使用相同的参数多次调用应该只调用一次", async () => {
const fn = vi.fn();
expect(fn).not.toBeCalled();
const handler = useMemorizeAsync(fn);
await handler("abc");
await handler("abc");
await handler("abc");
expect(fn).toBeCalledTimes(1);
await handler("def");
await handler("def");
await handler("def");
expect(fn).toBeCalledTimes(2);
});
it("传入异步函数,使用相同的参数多次调用应该只调用一次", async () => {
const fn = vi.fn((r) => r());
const asyncFunc = () => new Promise((r) => setTimeout(fn(r), 200));
const handler = useMemorizeAsync(asyncFunc);
await handler("abc");
await handler("abc");
await handler("abc");
expect(fn).toBeCalledTimes(1);
await handler("def");
await handler("def");
await handler("def");
expect(fn).toBeCalledTimes(2);
});
});
只执行一次的函数
ts
/**
* 自会让函数调用一次
* @param func - 要调用的函数
* @param thisArg - func 调用时 this 的指向
* @returns 新的函数
*/
const caches = new WeakSet();
export function once(func: Function, thisArg?: object): Function {
return function (...args: unknown[]) {
if (caches.has(func)) {
return;
}
caches.add(func);
func.apply(thisArg, args);
};
}
js
/**
* 自会让函数调用一次
* @param func - 要调用的函数
* @param thisArg - func 调用时 this 的指向
* @returns 新的函数
*/
const caches = new WeakSet();
export function once(func, thisArg = null) {
return function (...args) {
if (caches.has(func)) {
return;
}
caches.add(func);
func.apply(thisArg, args);
};
}
获取对象指定 key 的值成为一个新值
ts
/**
* 在一个对象中挑选一个 key, 然后返回新对象 pick({a:1, b:2}, 'a', 'c')
* @param source - 源对象
* @param keys - 挑选的 key
* @returns 处理后的新对象
*/
export function pick<T extends object, K extends keyof T>(
source: T,
...keys: K[]
): Pick<T, K> {
const target: any = Object.create(null);
keys.forEach((key) => {
target[key] = source[key];
});
return target;
}
js
/**
* 在一个对象中挑选一个 key, 然后返回新对象 pick({a:1, b:2}, 'a', 'c')
* @param source - 源对象
* @param keys - 挑选的 key
* @returns 处理后的新对象
*/
export function pick(source, ...keys) {
const target = Object.create(null);
keys.forEach((key) => {
target[key] = source[key];
});
return target;
}
排除对象指定 key 的值返回一个新值
ts
export function exclude<T extends object, K extends keyof T>(
source: T,
...keys: K[]
): Exclude<T, K> {
const target: any = Object.create(null);
Object.keys(source).forEach((key) => {
/* @ts-ignore */
if (!keys.includes(key)) {
target[key] = source[key];
}
});
return target;
}
js
export function exclude(source, ...keys) {
const target = Object.create(null);
Object.keys(source).forEach((key) => {
if (!keys.includes(key)) {
target[key] = source[key];
}
});
return target;
}
返回指定范围的随机数
ts
/**
* 返回指定范围内的随机数
* @param min - 最小值
* @param max - 最大值
* @returns 返回值
*/
export function range(min: number, max: number): number {
return Math.floor(Math.random() * (max - min + 1) + min);
}
js
/**
* 返回指定范围内的随机数
* @param min - 最小值
* @param max - 最大值
* @returns 返回值
*/
export function range(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
打乱数组元素顺序
ts
/**
* shuffle array items
* @param array
* @returns {Array}
*/
export function shuffle<T>(array: T[]): T[] {
if (array.length < 1) {
return [];
}
return [...array].sort(() => Math.random() - 0.5).reverse();
}
js
/**
* shuffle array items
* @param array
* @returns {Array}
*/
export function shuffle(array) {
if (array.length < 2) {
return [];
}
return [...array].sort(() => Math.random() - 0.5);
}
uuid
需要兼容低版本浏览器需要安装 uuid
ts
// 生成一个 uuid
import { v4 as uuidv4 } from "uuid";
export function uuid(): string {
if (typeof window.crypto !== "undefined") {
return window.crypto.randomUUID(); // v4
}
return uuidv4();
}
js
// 生成一个 uuid
import { v4 as uuidv4 } from "uuid";
export function uuid() {
if (typeof window.crypto !== "undefined") {
return window.crypto.randomUUID(); // v4
}
return uuidv4();
}
自增 id
ts
let __id = 0;
export const $uid = () => ++__id;