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 🙏

© 2026 – Pkg Stats / Ryan Hefner

zpy-tools

v1.1.5

Published

提供了日期格式化、日期计算、文件格式化、本地缓存处理、Base64转File、File转Base64、节流防抖、数组排序、数据结构转化、Markdown 转为适合微信分享的纯文本、深度比较两个对象是否包含相同的值等相关功能

Downloads

45

Readme

安装

npm install zpy-tools

导入

const zpyTools = require('zpy-tools');

格式化时间

/**
 * 格式化时间功能
 * 
 * @param {Date} date 时间对象
 * @param {String} format 格式化字符串,默认为 "YYYY-MM-DD HH:mm:ss"
*/
console.log(zpyTools.dateFormat(new Date(), 'yyyy-MM-dd'));   // "2024-05-20"
console.log(zpyTools.dateFormat(new Date(), 'hh:mm:ss'));   // "13:14:52"
console.log(zpyTools.dateFormat(new Date()));   // "2024-05-20 13:14:52"
/**
 * 获取两个日期之间的时间差
 * 
 * @param {Date} date1 日期对象1
 * @param {Date} date2 日期对象2
 * @param {String} unit 时间单位,可选值:'year', 'month', 'day', 'hour', 'minute', 'second'(默认)
 * @param {Number} decimal 保留小数位数,默认为 2
*/
const date1 = new Date('2024-01-01');
const date2 = new Date('2024-01-10');
console.log(zpyTools.dateDiff(date1, date2));   // 777600
console.log(zpyTools.dateDiff(date1, date2, 'minute'));   // 12960
console.log(zpyTools.dateDiff(date1, date2, 'hour'));   // 216
console.log(zpyTools.dateDiff(date1, date2, 'day'));   // 9
console.log(zpyTools.dateDiff(date1, date2, 'week'));   // 1.29
console.log(zpyTools.dateDiff(date1, date2, 'week', 0));   // 1
/**
 * 日期浮动
 * 
 * @param {Date} date 日期对象
 * @param {String} unit 浮动的单位,可选值:'year', 'month', 'day', 'hour', 'minute', 'second'
 * @param {Number} value 浮动的值
*/
const date = new Date("2023-04-01");
console.log(zpyTools.dateFloat(date, 'day', 5));  // '2023-04-06'
console.log(zpyTools.dateFloat(date, 'month', 3));  // '2023-07'
console.log(zpyTools.dateFloat(date, 'year', -1));  // '2022'
console.log(zpyTools.dateFloat(date, 'hour', 10));  // '2023-04-01 18'
console.log(zpyTools.dateFloat(date, 'minute', 30));  // '2023-04-01 08:30'
console.log(zpyTools.dateFloat(date, 'second', 60));  // '2023-04-01 08:01:00'

格式化文件大小

/**
 * 文件大小转换功能
 * 
 * @param {Number} size 文件大小
 * @param {String} fromUnit 源单位
 * @param {String} toUnit 目标单位
 * @param {Number} decimal 保留小数位数,默认为 2
*/
conosle.log(zpyTools.fileSizeConvert(2000, 'KB', 'MB'));   // 输出 "1.95 MB"
conosle.log(zpyTools.fileSizeConvert(1024, 'KB', 'MB', 2));   // 输出 "1.00 MB"
/**
 * 文件大小格式化功能
 * 
 * @param {Number} size 文件大小 - kb
 * @param {Number} decimal 保留小数位数,默认为 2
*/
conosle.log(zpyTools.fileSizeFormat(2000));   // 输出 "1.95 MB"
conosle.log(zpyTools.fileSizeFormat(1024, 2));   // 输出 "1.00 MB"
/**
 * File 文件转 Baes64
 * @param {File} file  文件
 * @returns {string}  base64 字符串
 */
conosle.log(zpyTools.fileToBase64(file));   // "data:image/*;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
/**
 * Baes64 文件转 File
 * @param {String} base64 base64字符串
 * @returns {File}  File 对象
 */
conosle.log(zpyTools.base64ToFile('data:image/*;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'));   // new File()

本地存储

/**
 * 设置 LocalStorage 项,并支持过期时间。
 * @param {string} key - 键名
 * @param {any} value - 键值
 * @param {number} [expiry] - 可选参数,过期时间(毫秒)
 */
zpyTools.setLocalStorageItem("user", { name: "Alice", age: 30 });
zpyTools.setLocalStorageItem("score", 100);
zpyTools.setLocalStorageItem("message", "Hello, world!");
zpyTools.setLocalStorageItem("", "invalid key"); // 抛出 TypeError
zpyTools.setLocalStorageItem("invalidValue", function() {}); // 抛出 TypeError

/**
 * 获取 LocalStorage 项,考虑过期时间。
 * @param {string} key - 键名
 * @returns {any | null} - 返回键对应的值或 null(如果已过期或不存在)
 */
console.log(zpyTools.getLocalStorageItem("user")); // { name: "Alice", age: 30 }
console.log(zpyTools.getLocalStorageItem("score")); // 100
console.log(zpyTools.getLocalStorageItem("message")); // "Hello, world!"
console.log(zpyTools.getLocalStorageItem("nonexistentKey")); // 返回 null
console.log(zpyTools.getLocalStorageItem("")); // 抛出 TypeError

/**
 * 清除 LocalStorage 项。
 * 如果提供了键名,则清除对应的单项;否则清除所有项。
 *
 * @param {string} [key] - 可选的键名,用于指定要清除的 LocalStorage 项。
 */
zpyTools.clearLocalStorageItem("user");
zpyTools.clearLocalStorageItem("score");
zpyTools.clearLocalStorageItem("message");
zpyTools.clearLocalStorageItem("nonexistentKey");
zpyTools.clearLocalStorageItem();

/**
 * 清除多个 LocalStorage 项。
 * @param {string[]} keys - 键名数组
 */
zpyTools.clearLocalStorageItem(["user", "score", "message"]);

数据验证

/**
 * 检查值是否为空
 * @param {*} value - 要检查的值
 * @returns {Boolean} - 如果值为空,则返回 true;否则返回 false
 */
console.log(zpyTools.isEmpty(null)); // true
console.log(zpyTools.isEmpty(undefined)); // true
console.log(zpyTools.isEmpty("")); // true
console.log(zpyTools.isEmpty([])); // true
console.log(zpyTools.isEmpty({})); // true
console.log(zpyTools.isEmpty(false)); // false
console.log(zpyTools.isEmpty(0)); // false
console.log(zpyTools.isEmpty("some string")); // false
console.log(zpyTools.isEmpty([1, 2, 3])); // false
console.log(zpyTools.isEmpty({ key: "value" })); // false
/**
 * 检查是否为合法的URL
 * @param {string} url - 要检查的URL字符串
 * @returns {Boolean} - 如果是合法的URL,则返回 true;否则返回 false
 */
console.log(zpyTools.isURL("https://www.example.com")); // true
console.log(zpyTools.isURL("http://example.com/path?query=123")); // true
console.log(zpyTools.isURL("ftp://example.com")); // false, 不支持 ftp 协议
console.log(zpyTools.isURL("")); // false
console.log(zpyTools.isURL("   ")); // false
console.log(zpyTools.isURL(123)); // 抛出 TypeError
/**
 * 检查是否为合法的电子邮件地址
 * @param {string} email - 要检查的电子邮件字符串
 * @returns {Boolean} - 如果是合法的电子邮件,则返回 true;否则返回 false
 */
console.log(zpyTools.isEmail("[email protected]")); // true
console.log(zpyTools.isEmail("[email protected]")); // true
console.log(zpyTools.isEmail("[email protected]")); // true
console.log(zpyTools.isEmail("invalid-email")); // false
console.log(zpyTools.isEmail("")); // false
console.log(zpyTools.isEmail("   ")); // false
console.log(zpyTools.isEmail(123)); // 抛出 TypeError
/**
 * 检查是否为合法的中国手机号码
 * @param {string|number} phone - 要检查的手机号码,可以是字符串或数字
 * @returns {Boolean} - 如果是合法的手机号码,则返回 true;否则返回 false
 */
console.log(zpyTools.isMobile("13800138000")); // true
console.log(zpyTools.isMobile(13800138000)); // true
console.log(zpyTools.isMobile("12345678901")); // false, 不符合中国手机号码格式
console.log(zpyTools.isMobile("")); // false
console.log(zpyTools.isMobile("   ")); // false
console.log(zpyTools.isMobile("abc123")); // false, 包含非数字字符
console.log(zpyTools.isMobile(null)); // 抛出 TypeError

工具包

/**
 * 获取数据类型
 * @param {*} value - 值
 * @returns {String} 数据类型
 */
console.log(zpyTools.getDataType(123)); // "number"
console.log(zpyTools.getDataType("hello")); // "string"
console.log(zpyTools.getDataType(true)); // "boolean"
console.log(zpyTools.getDataType([])); // "array"
console.log(zpyTools.getDataType(new Date())); // "date"
console.log(zpyTools.getDataType(/abc/)); // "regexp"
console.log(zpyTools.getDataType(null)); // "null"
console.log(zpyTools.getDataType(undefined)); // "undefined"
console.log(zpyTools.getDataType({})); // "object"
console.log(zpyTools.getDataType(function() {})); // "function"
/**
 * 对象深拷贝
 * @param {*} data - 值
 * @returns {*} 拷贝后的值
 */
console.log(zpyTools.deepClone({name: "对象深拷贝"}));   // {name: "对象深拷贝"}
/**
 * 数组排序
 * 对一维数组或二维数组(对象数组)进行排序。
 * 根据指定的键对对象数组进行排序,并且可以处理混合了数字和字符串的值,确保数字部分被正确解析和比较。
 * 此外,该函数支持正序和倒序排序,并允许用户通过提供 locales 和 compareOptions 来定制字符串比较的行为。
 * @param {Array} arr - 要排序的数组
 * @param {Object} options - 排序选项
 *    key - 排序的键名,默认为空
 *    isDesc - 是否降序,默认为true
 *    locales - 比较时使用的本地化信息,默认为空
 *    ...compareOptions - 其他用于比较的选项,例如sensitivity等
 * @returns {Array} 排序后的数组
*/
const numbers = [10, 2, 33];
console.log(zpyTools.sortArray(numbers));  // 输出 [2, 10, 33]

// 对一维数组进行降序排序
console.log(zpyTools.sortArray(numbers, { isDesc: true }));  // [33, 10, 2]

// 对对象数组按照特定键进行升序排序
const objects = [{ name: 'Alice', age: 30 }, { name: 'Bob', age: 25 }];
console.log(zpyTools.sortArray(objects, { key: 'age' }));  // [{ name: 'Bob', age: 25 }, { name: 'Alice', age: 30 }]

// 对对象数组按照特定键进行降序排序,并使用德语规则进行字符串比较
console.log(zpyTools.sortArray(objects, {
  key: 'name',
  isDesc: false,
  locales: 'de',
  compareOptions: { sensitivity: 'base' }
}));  // [{ name: 'Bob', age: 25 }, { name: 'Alice', age: 30 }]
/**
 * 将数组拼接成字符串
 * @param {*} value - 值,可以是数组或字符串
 * @param {String} [separator=","] - 分隔符,默认为逗号
 * @returns {String} 拼接后的字符串
 */
console.log(zpyTools.arrayToString(["apple", "banana", "orange"])); // "apple,banana,orange"
console.log(zpyTools.arrayToString("already a string")); // "already a string"
console.log(zpyTools.arrayToString([])); // ""
console.log(zpyTools.arrayToString(null)); // ""
console.log(zpyTools.arrayToString([1, 2, 3], "-")); // "1-2-3"
/**
 * 将字符串拆分成数组
 * @param {*} value - 值,可以是字符串或数组
 * @param {String} [separator=","] - 分隔符,默认为逗号
 * @returns {Array} 拆分后的数组
 */
console.log(zpyTools.stringToArray("apple, banana, orange")); // ["apple", "banana", "orange"]
console.log(zpyTools.stringToArray(["apple", "banana", "orange"])); // ["apple", "banana", "orange"]
console.log(zpyTools.stringToArray("  apple ,  banana  , orange  ")); // ["apple", "banana", "orange"]
console.log(zpyTools.stringToArray("")); // []
console.log(zpyTools.stringToArray(null)); // []
/**
 * 将扁平数组转换为树形结构
 * @param {Array} items - 扁平数组,每个元素包含 id 和 parentId 属性
 * @param {String} [idKey='id'] - 表示唯一标识的键名,默认为 'id'
 * @param {String} [parentIdKey='parentId'] - 表示父级标识的键名,默认为 'parentId'
 * @param {*} [rootValue=null] - 根节点的父级标识值,默认为 null
 * @returns {Array} 转换后的树形结构数组
 */
const flatArray = [
  { id: 1, parentId: null, name: 'Root' },
  { id: 2, parentId: 1, name: 'Child 1' },
  { id: 3, parentId: 1, name: 'Child 2' },
  { id: 4, parentId: 2, name: 'Grandchild 1' }
];
console.log(zpyTools.arrayToTree(flatArray));
// [
//     {
//         "id": 1,
//         "parentId": null,
//         "name": "Root",
//         "children": [
//             {
//                 "id": 2,
//                 "parentId": 1,
//                 "name": "Child 1",
//                 "children": [
//                     {
//                         "id": 4,
//                         "parentId": 2,
//                         "name": "Grandchild 1",
//                         "children": []
//                     }
//                 ]
//             },
//             {
//                 "id": 3,
//                 "parentId": 1,
//                 "name": "Child 2",
//                 "children": []
//             }
//         ]
//     }
// ]
/**
 * 将树形结构转换为数组
 * @param {Object} tree - 树形结构的根节点
 * @param {Array} [result=[]] - 用于收集结果的数组,可选,默认为空数组
 * @returns {Array} 转换后的数组
 */
const tree = {
  id: 1,
  name: 'root',
  children: [
    { id: 2, name: 'child1', children: [] },
    { id: 3, name: 'child2', children: [{ id: 4, name: 'grandchild', children: [] }] }
  ]
};
console.log(zpyTools.treeToArray(tree));
// [
//     {
//         "id": 1,
//         "name": "root",
//         "children": [
//             {
//                 "id": 2,
//                 "name": "child1",
//                 "children": []
//             },
//             {
//                 "id": 3,
//                 "name": "child2",
//                 "children": [
//                     {
//                         "id": 4,
//                         "name": "grandchild",
//                         "children": []
//                     }
//                 ]
//             }
//         ]
//     },
//     {
//         "id": 2,
//         "name": "child1",
//         "children": []
//     },
//     {
//         "id": 3,
//         "name": "child2",
//         "children": [
//             {
//                 "id": 4,
//                 "name": "grandchild",
//                 "children": []
//             }
//         ]
//     },
//     {
//         "id": 4,
//         "name": "grandchild",
//         "children": []
//     }
// ]
/**
 * 获取指定节点的父节点的 key 值
 * @param {Array} tree - 树形结构数组
 * @param {String} value - 目标叶子节点的 key 值
 * @param {Array} currentPath - 当前路径,用于递归调用
 * @returns {Array} 父节点的 key 值数组,如果没有找到,则返回 null
 */
const tree = [
  {
    key: 'root1',
    children: [
      { key: 'child1', children: [{ key: 'leaf1' }, { key: 'leaf2' }] },
      { key: 'child2', children: [{ key: 'leaf3' }] }
    ]
  },
  {
    key: 'root2',
    children: [
      { key: 'child3', children: [{ key: 'leaf4' }] }
    ]
  }
];
console.log(zpyTools.getParentKeys(tree, 'leaf2')); // ['root1', 'child1']
/**
 * 深度比较两个对象是否包含相同的值
 * @param {Object} obj1 - 第一个对象
 * @param {Object} obj2 - 第二个对象
 * @returns {Boolean} - 如果两个对象的值完全相同,返回true,否则返回false
 */
const objA = { a: 1, b: { c: 2 } };
const objB = { a: 1, b: { c: 2 } };
console.log(zpyTools.hasObjectsEqual(objA, objB)); // true

const objC = { a: 1, b: { c: 3 } };
console.log(zpyTools.hasObjectsEqual(objA, objC)); // false

const circularA = {};
circularA.self = circularA;
const circularB = {};
circularB.self = circularB;
console.log(zpyTools.hasObjectsEqual(circularA, circularB)); // true
/**
 * 防抖函数工厂
 * @param {Function} fn - 需要执行的函数
 * @param {Number} [delay=500] - 延迟时间,默认500ms
 * @param {Boolean} [immediate=false] - 是否立即执行,默认false
 * @returns {Function} 返回防抖包装后的函数
 */
const debouncedFunction = zpyTools.debounce(function () {
  console.log('This will be logged after 500ms of no new calls.');
}, 500);
setInterval(debouncedFunction, 200); // 每200毫秒触发一次,但实际每500毫秒最多执行一次

// 立即执行版本示例用法:
const immediatelyDebouncedFunction = zpyTools.debounce(function () {
  console.log('This will execute immediately and then wait for 500ms.');
}, 500, true);
immediatelyDebouncedFunction(); // This will execute immediately and then wait for 500ms.
/**
 * 节流函数工厂
 * @param {Function} fn - 需要执行的函数
 * @param {Number} [interval=1000] - 间隔时间,默认1000ms
 * @returns {Function} 返回节流包装后的函数
 */
const throttledFunction = zpyTools.throttle(function () {
  console.log('This will be logged at most once every second.');
}, 1000);

setInterval(throttledFunction, 250); // 每250毫秒触发一次,但实际每秒最多执行一次
/**
 * 获取URL中的参数
 * @param {String} [url] - URL字符串,默认为当前页面的URL
 * @returns {Object} 包含URL参数的对象
 */
console.log(zpyTools.getUrlParams('http://example.com/?name=John&age=30&name=Jane'));
// {
//     "name": [
//         "John",
//         "Jane"
//     ],
//     "age": "30"
// }
/**
 * 将参数添加到URL
 * @param {string} url 基础URL
 * @param {Object} params 要添加的参数对象
 * @returns {string} 添加了参数后的URL
 */
console.log(zpyTools.addParamsToUrl('http://example.com', { param1: 'value1', param2: 'value2' })); // http://example.com?param1=value1&param2=value2
/**
 * 将数组按给定的属性进行分类
 * @param {Array} array 需要分类的数组
 * @param {String} property 用于分类的属性名
 * @returns {Object} 分类结果,键为属性值,值为对应的数组
 */
const data = [
  { id: 1, category: 'fruit', name: 'apple' },
  { id: 2, category: 'vegetable', name: 'carrot' },
  { id: 3, category: 'fruit', name: 'banana' },
  { id: 4, category: 'vegetable', name: 'broccoli' },
  { id: 5, name: 'unknown' } // 缺少 category 属性
];

console.log(zpyTools.classifyBy(data, 'category'));
// {
//     "fruit": [
//         {
//             "id": 1,
//             "category": "fruit",
//             "name": "apple"
//         },
//         {
//             "id": 3,
//             "category": "fruit",
//             "name": "banana"
//         }
//     ],
//     "vegetable": [
//         {
//             "id": 2,
//             "category": "vegetable",
//             "name": "carrot"
//         },
//         {
//             "id": 4,
//             "category": "vegetable",
//             "name": "broccoli"
//         }
//     ],
//     "undefined": [
//         {
//             "id": 5,
//             "name": "unknown"
//         }
//     ]
// }
console.log(zpyTools.classifyBy(data, 'name'));
// {
//     "apple": [
//         {
//             "id": 1,
//             "category": "fruit",
//             "name": "apple"
//         }
//     ],
//     "carrot": [
//         {
//             "id": 2,
//             "category": "vegetable",
//             "name": "carrot"
//         }
//     ],
//     "banana": [
//         {
//             "id": 3,
//             "category": "fruit",
//             "name": "banana"
//         }
//     ],
//     "broccoli": [
//         {
//             "id": 4,
//             "category": "vegetable",
//             "name": "broccoli"
//         }
//     ],
//     "unknown": [
//         {
//             "id": 5,
//             "name": "unknown"
//         }
//     ]
// }
console.log(zpyTools.classifyBy([], 'category')); // {}
console.log(zpyTools.classifyBy(data, '')); // 抛出错误:The property name cannot be empty or null.

开源协议

ISC