npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@zj-library/utils

v1.0.4

Published

工具函数

Readme

工具函数

一些常见的工具函数

color

mix(模拟 SCSS mix() 函数,混合两种颜色)

/**
 * 颜色相关的处理
 *
 * @author 左建
 * @exports mix, darken,  light
 */
/**
 * 模拟 SCSS mix() 函数,混合两种颜色
 *
 * @param color1 第一种颜色(十六进制,如 #1963dc)
 * @param color2 第二种颜色(十六进制,如 #ffffff)
 * @param weight 第一种颜色的权重(0-100 或 "0%-100%",默认 50)
 * @returns 混合后的十六进制颜色
 */
export declare function mix(color1: string, color2: string, weight?: number | string): string;

light(与白色混合,传10表示变浅到原来的10%, 注意这点是变浅到原来10%, 意思是传10只有传入颜色的10%,很浅)

/**
 * 与白色混合,传10表示变浅到原来的10%, 注意这点是变浅到原来10%, 意思是传10只有传入颜色的10%,很浅
 *
 * @param color 第一种颜色(十六进制,如 #1963dc)
 * @param weight 第一种颜色的权重(0-100 或 "0%-100%",默认 50)
 * @returns 混合后的十六进制颜色
 */
export declare function light(color: string, weight?: number | string): string;

darken(与黑色混合 传10表示加深10%,注意这点是加深10%,意思是传入颜色加深10%)

/**
 * 与黑色混合 传10表示加深10%,注意这点是加深10%,意思是传入颜色加深10%
 *
 * @param color 第一种颜色(十六进制,如 #1963dc)
 * @param weight 第一种颜色的权重(0-100 或 "0%-100%",默认 50)
 * @returns 混合后的十六进制颜色
 */
export declare function darken(color: string, weight?: number | string): string;

event-emitter

type FnType = (...args: any[]) => void;

EventEmitter(事件发射器)

/**
 * 事件发射器
 *
 * @class
 * @class
 */
export default class EventEmitter {
    private events;
    private paddingEvents;
    constructor();
    /**
     * 监听事件
     *
     * @param event 事件名称
     * @param callback 回调函数
     */
    on(event: string | Array<string>, callback: FnType): void;
    /**
     * 移除监听事件,如果不传任何参数,则清空所有
     *
     * @param event 事件名称
     * @param callback 回调函数,如果不传则清空该事件下的所有侦听
     */
    off(event?: string | Array<string>, callback?: FnType): void;
    /**
     * 监听一次事件
     *
     * @param event 事件名称
     * @param callback 回调函数
     */
    once(event: string, callback: FnType): void;
    /**
     * 触发事件
     *
     * @param event 事件名称
     * @param args 回调函数的参数
     */
    emit(event: string, ...args: any[]): void;
}

load

type TaskType = () => Promise<any>;

loadTaskWithRetry(带有错误重试功能的加载函数)

/**
 * 带有错误重试功能的加载函数
 *
 * @param task 任务
 * @param onError 错误时的回调
 */
export declare function loadTaskWithRetry(task: TaskType, onError?: (retry: Function, fail: Function) => void): Promise<any>;

loadTaskRetryFixCount(固定重试次数)

/**
 * 固定重试次数
 *
 * @param task 任务
 * @param count 重试次数,默认一次
 */
export declare function loadTaskRetryFixCount(task: TaskType, count?: number): Promise<any>;

TaskQueen(异步任务队列)

/**
 * 异步任务队列
 *
 * @class
 * @class
 * @param limit 队列的窗口大小,默认为3
 */
export declare class TaskQueen {
    private runningCount;
    private limit;
    private queen;
    /**
     * 构造函数
     *
     * @param limit 队列的窗口大小,默认为3
     */
    constructor(limit?: number);
    /**
     * 运行任务
     *
     * @param task 任务
     */
    run(task: TaskType): Promise<void>;
}

loadTasks(批量执行任务)

/**
 * 批量执行任务
 *
 * @param tasks 任务
 * @param success 成功回调
 * @param fail 失败回调
 * @param windowSize 窗口大小
 */
export declare function loadTasks(tasks: TaskType[], success?: (res: any, index: number) => void, fail?: (err: any, index: number) => void, windowSize?: number): void;

utils

sleep(等待多少秒钟,单位为毫秒)

/**
 * 等待多少秒钟,单位为毫秒
 *
 * @example
 *     sleep(20).then(() => {
 *     // 做点什么
 *     }) 等待20毫秒之后
 *
 * @param ms 传入的值
 */
export declare function sleep(ms: number): Promise<void>;

isObject(是否是对象)

/**
 * 是否是对象
 *
 * @example
 *     isObject({}) => true; isObject([]) => false
 *
 * @param value 传入的值
 */
export declare function isObject(value: any): boolean;

deepClone(深度克隆, 会克隆原型和symbol)

/**
 * 深度克隆, 会克隆原型和symbol
 *
 * @example
 *     deepClose({a: 1, b: 2, c: {d: 'e'}, f: [1, 2], g: Symbol('f'), date: new Date()}) =>
 *     新对象{a: 1, b: 2, c: {d: 'e'}, f: [1, 2], g: Symbol('f'), date: xxx}, date为以前的对象
 *     这点针对普通对象和数组进行克隆,其他对象不进行任何操作
 *
 * @param value 传入的指
 */
export declare function deepClone<T>(value: T): T;

isArrayOrObject(是否是普通对象或者数组)

/**
 * 是否是普通对象或者数组
 *
 * @example
 *     isArrayOrObject({}) => true
 *     isArrayOrObject([]) => true
 *     isArrayOrObject(new Date()) => false
 *     isArrayOrObject(new Set()) => false
 *     .... 其他均为false
 *
 * @param value 传入的指
 */
export declare function isArrayOrObject(value: any): boolean;

merge(合并对象)

/**
 * 合并对象
 *
 * @example
 *     const target = {a: 'b', e: [2, {f: 'd'}, {g: 'h'}] }; const source = {c: 'd', e: [1]}
 *     merge(target, false, source) => {a: 'b', c: 'd', e: [1]}
 *     merge(target, true, source) => {a: 'b', c: 'd', e: [1, {f: 'd'}, {g: 'h'}]}
 *
 * @param target 目标对象
 * @param mergeArray 是否合并数组
 * @param sources 源对象
 */
export declare function merge(target: any, mergeArray: boolean, ...sources: any[]): any;

isEmpty(判断值是否为空)

/**
 * 判断值是否为空
 *
 * @example
 *     // 默认将0也判定为空
 *     isEmpty(0) => true
 *     // 将0判定为不为空
 *     isEmpty(0, false) => false
 *
 *     // 空对象判定为空
 *     isEmpty({}) => true;
 *     // 空数组判定为空
 *     isEmpty([]) => true
 *
 * @param value 判断值, 常规的空值:'', null, undefined, NaN, false 等都会判定为空
 * @param isIncludeZero 是否包含0
 */
export declare function isEmpty(value: any, isIncludeZero?: boolean): boolean;

isNotEmpty(判断值是否不为空,相当于 !isEmpty(value))

/**
 * 判断值是否不为空,相当于 !isEmpty(value)
 *
 * @example
 *     // 默认将0也判定为0
 *     isNotEmpty(0) => false
 *     // 将0判定为不为空
 *     isNotEmpty(0, false) => true
 *
 *     // 空对象判定为空
 *     isNotEmpty({}) => false;
 *     // 空数组判定为空
 *     isNotEmpty([]) => false
 *
 * @param value 判断值, 常规的空值:'', null, undefined, NaN, false 等都会判定为空
 * @param isIncludeZero 是否包含0
 */
export declare function isNotEmpty(value: any, isIncludeZero?: boolean): boolean;

addPercentage(数字后面添加 %)

/**
 * 数字后面添加 %
 *
 * @example
 *     addPercentage(10) => 10%
 *     addPercentage(0.4569, true) => 45.7%
 *     addPercentage('10%') => 10%
 *     其他类型的值 返回空字符串
 *
 * @param value 传入的数值
 * @param isDecimal 是否处理小数:0.8534 => 85.3
 */
export declare function addPercentage(value: any, isDecimal?: boolean): string;

getPropertyValueByPath(从对象中获取属性值)

/**
 * 从对象中获取属性值
 *
 * @example
 *     const obj = {a:{b: [1]}}
 *     getPropertyValueByPath(obj, 'a.b[0]') => 1
 *     getPropertyValueByPath(obj, 'a.b[1]', '--') => --
 *
 * @param obj 传入的对象
 * @param path 传入的path路径:a.b[0].c
 * @param placeholder 为空时的占位符
 */
export declare function getPropertyValueByPath(obj: Record<any, any>, path: string, placeholder?: any): any;

setPropertyValueByPath(设置对象的属性值)

/**
 * 设置对象的属性值
 *
 * @example
 *     const obj = {a:{b: [[{e: 'd'}]]}}
 *     setPropertyValueByPath(obj, 'a.b[0][1].c', 'g') => {a:{b: [[{e: 'd'}, {c: 'g'}]]}}
 *
 * @param obj 传入的对象
 * @param path 传入的path路径
 * @param value 设置的值
 */
export declare function setPropertyValueByPath<T>(obj: T, path: string, value: any): T;

kebabToCamelCase(Kebab("-"分割)转为小驼峰(第一个单词全小写,后续单词首字母大写))

/**
 * Kebab("-"分割)转为小驼峰(第一个单词全小写,后续单词首字母大写)
 *
 * @example
 *     kebabToCamelCase('hello-world') => helloWorld
 *     kebabToCamelCase('Hello-World') => helloWorld
 *     kebabToCamelCase('HeLlo') => hello
 *
 * @param str 输入的横杠分隔字符串(如 "hello-world"或"Hello-World")=> helloWorld
 * @returns 小驼峰格式字符串(如 "helloWorld")
 */
export declare function kebabToCamelCase(str: string): string;

camelCaseToKebab(小驼峰转为kebab("-"分割))

/**
 * 小驼峰转为kebab("-"分割)
 *
 * @example
 *     camelCaseToKebab("helloWorld") => hello-world
 *     camelCaseToKebab("FooBar") => foo-bar
 *
 * @param str 输入的横杠分隔字符串(如 "helloWorld"或"HelloWorld")=> hello-world
 * @returns 小驼峰格式字符串(如 "hello-world")
 */
export declare function camelCaseToKebab(str: string): string;

getCameCaseObject(将对象键转为小驼峰)

/**
 * 将对象键转为小驼峰
 *
 * @example
 *     const obj = {a: 'b', 'foo-bar': 'fooBar', CameCase: 'CameCase'}
 *     getCameCaseObject(obj) => {a: 'b', fooBar: 'fooBar', cameCase: 'CameCase'}
 *
 * @param object 传入的对象
 */
export declare function getCameCaseObject<T>(object: T): T;

noop(空函数,常用于占位,避免重复创建函数)

/** 空函数,常用于占位,避免重复创建函数 */
export declare function noop(): void;

polling(轮询函数, 带有暂停和恢复执行)

/**
 * 轮询函数, 带有暂停和恢复执行
 *
 * @example
 *     const task = async () => {}
 *     const pollHandler = polling(task)
 *     pollHandler.paused() // 暂停
 *     pollHandler.resumed() // 恢复执行
 *
 * @param task 轮询一个Promise任务
 * @param success 成功时的回调
 * @param fail 失败的回调
 * @param immediate 是否立即开始
 * @param step 每一次轮询后,增加的时间,单位毫秒
 * @param startWaitTime 初始等待时间(毫秒)
 */
export declare function polling(task: () => Promise<any>, success?: (res: any) => void, fail?: (res: any) => void, immediate?: boolean, step?: number, startWaitTime?: number): {
    /** 暂停执行 */
    paused(): void;
    /**
     * 恢复执行
     *
     * @param isResetTime 是否重置等待时间为startWaitTime
     */
    resumed(isResetTime?: boolean): void;
};

isPrimitive(判断一个值是否是原始类型)

/**
 * 判断一个值是否是原始类型
 *
 * @example
 *     isPrimitive(对象) => false
 *     isPrimitive(() => {}) => false
 *     其他情况均为true
 *
 * @param value 传入的值
 */
export declare function isPrimitive(value: any): boolean;

isEquals(判断两个值是否相等, 原始值通过Object.is判断,非原始值递归判断)

/**
 * 判断两个值是否相等, 原始值通过Object.is判断,非原始值递归判断
 *
 * @example
 *     isEquals('foo', 'bar') => false
 *     isEquals({a: 'b', c: {d: 'e'}}, 'bar') => false
 *     isEquals({a: 'b', c: {d: 'e'}}, {a: 'b', c: {d: 'e'}}) => true
 *
 * @param v1 值一
 * @param v2 值二
 */
export declare function isEquals(v1: any, v2: any): boolean;

uniqueArray(数组去重,重的概念:原始类型用Object.is比较,非原始类型递归Object.is比较)

/**
 * 数组去重,重的概念:原始类型用Object.is比较,非原始类型递归Object.is比较
 *
 * @example
 *     // 内部使用isEquals去比较
 *     uniqueArray([{a: 'b', c: 'd'}, { a: 'b' }, {a: 'b'}, 1, 1, 'foo', 'foo', 'bar']) => [{a: 'b', c: 'd'}, {a: 'b'}, 1,'foo','bar']
 *
 * @param list 需要去重的数组
 */
export declare function uniqueArray<T>(list: Array<T>): T[];

formatDate(格式化时间)

/**
 * 格式化时间
 *
 * @example
 *     formatDate() => 当前时间,比如:2025-10-10
 *     formatDate(new Date(2021, 9, 15, 23, 59, 9), 'yyyy-mm-dd hh:MM:ss') => 2021-10-15 23:59:09
 *
 * @param dateTime 需要格式化的时间戳
 * @param formatStr 格式化规则 yyyy:mm:dd|yyyy:mm|yyyy年mm月dd日|yyyy年mm月dd日 hh时MM分等,可自定义组合 默认yyyy-mm-dd
 * @returns 返回格式化后的字符串
 */
export declare function formatDate(dateTime?: any, formatStr?: string): string;

timeFrom(时间戳转为多久之前)

/**
 * 时间戳转为多久之前
 *
 * @example
 *     // 以当前时间为基准
 *     timeFrom() => 刚刚
 *     // 指定时间距离当前时间过去了多少
 *     timeFrom(new Date(2025, 9, 10, 18, 10, 9).getTime()) => 2025-10-10 或 刚刚 或 几分钟前 或 几个小时前 或 几天前
 *     timeFrom(new Date(2025, 9, 10, 18, 10, 9).getTime(), 'yyyy-mm-dd hh:MM:ss') => 2025-10-10 18:10:09 或 刚刚 或 几分钟前 或 几个小时前 或 几天前
 *     timeFrom(new Date(2025, 9, 10, 18, 10, 9).getTime(), false) => 2025-10-10 或 刚刚 或 几分钟前 或 几个小时前 或 几天前 或 几个月前 或 几年前
 *
 * @param timestamp 时间戳
 * @param format 格式化规则如果为时间格式字符串,超出一定时间范围,返回固定的时间格式; 如果为布尔值false,无论什么时间,都返回多久以前的格式
 * @returns 转化后的内容
 */
export declare function timeFrom(timestamp?: null | string | number, format?: string | false): string;

genSkus(生成sku数组,数组里面每一项都是一条sku组合,其实就是计算笛卡尔积。)

/**
 * 生成sku数组,数组里面每一项都是一条sku组合,其实就是计算笛卡尔积。
 *
 * @example
 *     genSkus({color: ['red', 'green', 'blue'], shape: ['circle', 'round'], size: ['small', 'medium', 'large']}) =>
 *     生成 [{color: 'red', size: 'small', shape: 'circle'}, ...]
 *
 * @param attrs 属性列表
 * @returns Skus数组
 */
export declare function genSkus<T extends Record<string, readonly any[]>>(attrs: T): Array<{
    [K in keyof T]: T[K][number];
}>;

normalizeUrl(去除地址中前后的斜杠)

/**
 * 去除地址中前后的斜杠
 *
 * @example
 *     normalizeUrl('//a/b/c//') => 'a/b/c'
 *     normalizeUrl('/a/b/c/') => 'a/b/c'
 *
 * @param url 属性列表
 */
export declare function normalizeUrl(url: string): string;