零延时计时器
在浏览器中,setTimeout()/setInterval() 的每调用一次定时器的最小间隔是 4ms,这通常是由于函数嵌套导致(嵌套层级达到一定深度)。
此函数模拟一个零延时的 setTimeout
,通过 postMessage
和 message
事件来实现。避免浏览器中 setTimeout
和 setInterval
的延迟。
ts
(function () {
var timeouts = [];
var messageName = 'zero-timeout-message';
// 保持 setTimeout 的形态,只接受单个函数的参数,延迟始终为 0。
function setZeroTimeout(fn) {
timeouts.push(fn);
window.postMessage(messageName, '*');
}
function handleMessage(event) {
if (event.source == window && event.data == messageName) {
event.stopPropagation();
if (timeouts.length > 0) {
var fn = timeouts.shift();
fn();
}
}
}
window.addEventListener('message', handleMessage, true);
// 把 API 添加到 window 对象上
window.setZeroTimeout = setZeroTimeout;
})();
findLast
从数组中查找满足条件的最后一个元素,返回该元素或 undefined
。
ts
/**
* Finds the last element in the array that satisfies the provided predicate function.
*
* @param array The array to search.
* @param predicate The condition function to evaluate each element.
* @returns The last element that satisfies the predicate, or undefined if none do.
*/
function findLast<T>(array: Array<T>, predicate: (value: T, index: number, obj: T[]) => boolean): T | undefined {
let cursor = array.length;
while (cursor--) {
if (predicate(array[cursor], cursor, array)) {
return array[cursor];
}
}
return undefined;
}
Clone Deep
深度复制一个对象或数组,避免引用问题。
ts
/**
* Creates a deep copy of a value, preserving the structure of objects and arrays.
*
* @param value The value to be cloned.
* @returns A deep clone of the input value.
*/
function cloneDeep<T>(value: T): T {
if (typeof value !== 'object') {
return value;
}
if (Array.isArray(value)) {
return value.map(cloneDeep) as typeof value;
}
return Object.keys(value).reduce((acc, key) => {
acc[key as keyof T] = cloneDeep(value[key as keyof T]);
return acc;
}, {} as T);
}
数组切割
将一个数组分割成多个小数组,每个小数组的长度不超过 chunkSize
。
ts
/**
* Splits an array into chunks of a given size.
*
* @param array The array to split.
* @param chunkSize The size of each chunk.
* @returns An array of arrays, where each inner array is a chunk.
*/
function split(array: any[], chunkSize: number) {
const result = [];
for (let i = 0; i < array.length; i += chunkSize) {
result.push(array.slice(i, i + chunkSize));
}
return result;
}
Omit
创建一个新的对象,去除指定的属性。
ts
/**
* Creates a new object with the specified keys omitted.
*
* @param object The original object.
* @param keys The keys to omit from the object.
* @returns A new object without the omitted keys.
*/
function omit<T, K extends keyof T>(object: T, keys: K[]) {
const stringKeys = new Set(keys.map(String));
const savedKeys = Object.keys(object).filter(
(key) => !stringKeys.has(key)
) as Array<Exclude<keyof T, K>>;
return pick(object, savedKeys);
}
Pick
从对象中挑选指定的属性,生成一个新的对象。
ts
/**
* Creates a new object with only the truthy values of the specified keys.
*
* @param object The original object.
* @param keys The keys to check for truthy values.
* @returns A new object with truthy values only.
*/
function pick<T, K extends keyof T>(object: T, keys: K[]) {
return keys.reduce((result, key) => {
if (object[key]) {
result[key] = object[key];
}
return result;
}, {} as Pick<T, K>);
}
遍历对象,生成一个新对象
对对象的每个值进行转换,并生成一个新对象。
ts
/**
* Iterates through an object and generates a new object with the transformed values.
*
* @param byKey The original object.
* @param callback The function that transforms each value.
* @returns A new object with the transformed values.
*/
export function mapValues<R extends any, M extends any>(
byKey: CollectionByKey<M>,
callback: (
member: M,
key: string,
index: number,
originalByKey: CollectionByKey<M>
) => R
): CollectionByKey<R> {
return Object.keys(byKey).reduce(
(newByKey: CollectionByKey<R>, key, index) => {
newByKey[key] = callback(byKey[key], key, index, byKey);
return newByKey;
},
{}
);
}
arrayToRecord
将数组转换为以某个字段为键的对象。
ts
/**
* Converts an array of objects to a record (key-value pair) based on a specified key.
*
* @param arr The array to convert.
* @param key The key to use for each object in the array.
* @returns A record where each key is the value of the specified key in the objects.
*/
const arrayToRecord = <K extends string | number | symbol, V extends { [key in K]?: any }>(
arr: V[],
key: K,
): Record<string, V> => {
const record: Record<string, V> = {} as Record<K, V>;
if (!Array.isArray(arr)) {
return {} as Record<K, V>;
}
arr.forEach(item => {
if (key in item) {
record[item[key]] = item;
}
});
return record;
};
arrayToMap
将数组转换为以某个字段为键的 Map
对象。
ts
/**
* Converts an array of objects to a Map based on a specified key.
*
* @param array The array to convert.
* @param key The key to use as the map's key.
* @returns A Map where each key is the value of the specified key in the objects.
*/
const arrayToMap = <T, K extends keyof T>(array: T[], key: K): Map<T[K], T> => {
const map = new Map<T[K], T>();
for (const item of array) {
if (item[key] !== undefined) {
map.set(item[key], item);
}
}
return map;
};
arrayGroupByKey
将数组根据某个字段的值进行分组,返回一个分组后的对象。
ts
/**
* Groups an array of objects by the value of a specified key.
*
* @param array The array to group.
* @param key The key to group the array by.
* @returns An object where each key is a group key, and the value is an array of items in that group.
*/
const arrayGroupByKey = <T, K extends keyof T>(array: T[], key: K) =>
array.reduce(
(acc, cur) => {
const groupKeyValue: any = cur[key];
const prevItems = acc[groupKeyValue] ?? [];
return {
...acc,
[groupKeyValue]: [...prevItems, cur],
};
},
{} as Record<string | number, T[]>,
);
计算中英文字符串的长度
计算字符串的长度,中文字符算作 2 个单位,英文字符算作 1 个单位。
ts
/**
* Checks the length of a string where English characters count as 1, and Chinese characters count as 2.
*
* @param str The string to check.
* @returns The total length considering Chinese characters as double.
*/
const checkValueSize = str => {
let rxcn = /[\u4e00-\u9fa5]/,
num = 0
for (let i = 0, j = str.length; i < j; i++) {
let chr = str.charAt(i)
if (rxcn.test(chr)) {
num += 2
} else {
num += 1
}
}
return num
}
十六进制转为RGB
将十六进制颜色值转换为 RGB 格式。
ts
/**
* Converts a hex color code to an RGB format.
*
* @param hex The hex color code to convert.
* @returns The RGB representation of the color.
*/
function hex2Rgb(hex) { // 十六进制转为RGB
let rgb = []; // 定义rgb数组
if (/^\#[0-9A-F]{3}$/i.test(hex)) { // 判断是否为3位十六进制数
let sixHex = '#';
hex.replace(/[0-9A-F]/ig, function(kw) {
sixHex += kw + kw; // 转换为六位
});
hex = sixHex; // 保存回hex
}
if (/^#[0-9A-F]{6}$/i.test(hex)) { // 判断是否为六位十六进制数
hex.replace(/[0-9A-F]{2}/ig, function(kw) {
rgb.push(parseInt(kw,16)); // 转换为十进制
});
return `rgb(${rgb.join(',')})`; // 输出RGB
} else {
console.log(`Input ${hex} is wrong!`);
return 'rgb(0,0,0)';
}
}
RGB转为十六进制
将 RGB 颜色值转换为十六进制格式。
ts
/**
* Converts an RGB color to a hex code.
*
* @param rgb The RGB color to convert.
* @returns The hex representation of the color.
*/
function rgb2Hex(rgb) {
if (/^rgb\((\d{1,3}\,){2}\d{1,3}\)$/i.test(rgb)) { // Test for RGB format
let hex = '#';
rgb.replace(/\d{1,3}/g, function(kw) { // Extract RGB values
kw = parseInt(kw).toString(16); // Convert to hex
kw = kw.length < 2 ? 0 + kw : kw; // Ensure two digits
hex += kw;
});
return hex;
} else {
console.log(`Input ${rgb} is wrong!`);
return '#000'; // Return #000 for invalid input
}
}
生成随机颜色-十六进制格式
生成一个随机的十六进制颜色值。
ts
/**
* Generates a random color in hex format.
*
* @returns A random hex color code.
*/
function randomHexColor() {
return '#' + ('00000' + (Math.random() * 0x1000000 << 0).toString(16)).substr(-6);
}
生成随机颜色-RGB格式
生成一个随机的 RGB 颜色值。
ts
/**
* Generates a random color in RGB format.
*
* @returns A random RGB color.
*/
function randomRgbColor() { // 随机生成RGB颜色
const r = Math.floor(Math.random() * 256); // Random r value
const g = Math.floor(Math.random() * 256); // Random g value
const b = Math.floor(Math.random() * 256); // Random b value
return `rgb(${r},${g},${b})`; // Return RGB color
}
生成随机颜色-RGBA格式
生成一个随机的 RGBA 颜色值。
ts
/**
* Generates a random color in RGBA format.
*
* @returns A random RGBA color with an alpha value.
*/
function randomRgbaColor() { // 随机生成RGBA颜色
const r = Math.floor(Math.random() * 256); // Random r value
const g = Math.floor(Math.random() * 256); // Random g value
const b = Math.floor(Math.random() * 256); // Random b value
const alpha = Math.random(); // Random alpha value
return `rgb(${r},${g},${b},${alpha})`; // Return RGBA color
}
数组去重 unique
去除数组中的重复元素,返回一个新的数组。
ts
/**
* Removes duplicate values from an array.
*
* @param arr The array to remove duplicates from.
* @returns A new array with unique values.
*/
const unique = <T extends any>(arr: T[]): T[] => {
return [...new Set(arr)];
};
生成随机不重复 ID(1)
生成随机 ID,包含字母和数字。
ts
const urlAlphabet =
'useandom26T198340PX75pxJACKVERYMINDBUSHWOLFGQZbfghjklqvwyzrictil1b'
/**
* Generates a random unique ID.
*
* @param size The length of the ID.
* @returns A random unique ID.
*/
const nanoid = (size = 21) => {
let id = '';
let i = size;
while (i--) {
id += urlAlphabet[(Math.random() * 66) | 0];
}
return id;
}
生成随机不重复 ID(2)
生成一个基于当前时间戳和随机数的唯一 ID。
ts
/**
* Generates a random unique ID based on the current timestamp and random values.
*
* @returns A random unique ID.
*/
export const generateUniqueId = () => Date.now().toString(36) + Math.random().toString(36).slice(2);
快速生成自然数数组
生成一个包含从 0 开始的自然数数组的不同的实现方式。
ts
const n = 10000;
// 方法一 快
let i = 0;
new Array(n).fill(i++);
// 方法二 最慢
Array.from({ length: n }, (v, i) => i);
// 方法三 慢
[...Array(n).keys()];
// lodash 快
_.times(n);
数组打乱,随机排序
打乱数组的顺序,进行随机排序。
ts
arr.sort(() => Math.random() - 0.5);
isValidUrl
判断给定的字符串是否为有效的 URL。
ts
function isValidUrl(url: string) {
try {
new URL(url);
return true; // 格式正确
} catch (e) {
return false; // 格式错误
}
}