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

pen-it

v1.0.6

Published

用笔锚定记忆中的前端常用工具函数,一个轻量级的前端实用程序库,支持类型检查、日期/数字格式化、字符串操作、数据存储、深度克隆、数组操作、Cookie 以及浏览器 API

Readme

pen-it

用笔锚定记忆中的前端常用工具函数,一个轻量级的前端实用程序库,支持类型检查、日期/数字格式化、字符串操作、数据存储、深度克隆、数组操作、Cookie 以及浏览器 API

安装

pnpm add pen-it

使用

import { isArray, formatFull, deepClone, unique } from 'pen-it'

API

类型判断 — is

  • isArray(value) — 判断是否为数组。

    isArray([1, 2, 3])  // true
  • isObject(value) — 判断是否为对象(不含数组)。

    isObject({ a: 1 })  // true
  • is(val, type) — 通用类型判断(内部工具)。

    is([], 'Array')  // true
  • isFunction(val) — 判断是否为函数。

    isFunction(() => {})  // true
  • isAsyncFunction(val) — 判断是否为异步函数。

    isAsyncFunction(async () => {})  // true
  • isPromise(value) — 判断是否为 Promise。

    isPromise(Promise.resolve())  // true
  • isDate(val) — 判断是否为 Date 对象。

    isDate(new Date())  // true
  • isNumber(val) — 判断是否为数字(含 NaN/Infinity)。

    isNumber(42)  // true
  • isInt(val) — 判断是否为整数。

    isInt(42)  // true
  • isFloat(val) — 判断是否为浮点数。

    isFloat(3.14)  // true
  • isString(val) — 判断是否为字符串。

    isString('hello')  // true
  • isBoolean(val) — 判断是否为布尔值。

    isBoolean(true)  // true
  • isSymbol(value) — 判断是否为 Symbol。

    isSymbol(Symbol('foo'))  // true
  • isPrimitive(value) — 判断是否为原始类型。

    isPrimitive(42)  // true
  • isNull(val) — 判断是否为 null。

    isNull(null)  // true
  • isDef(val) — 判断是否不是 undefined。

    isDef('hello')  // true
  • isUnDef(val) — 判断是否为 undefined。

    isUnDef(undefined)  // true
  • isNullOrUnDef(val) — 判断是否为 null 或 undefined。

    isNullOrUnDef(null)  // true
  • isEmpty(value) — 判断是否为空(完备版:支持 Date/Map/Set 等)。

    isEmpty('')   // true
    isEmpty([])   // true
    isEmpty({})   // true
  • isEmptySv(value) — 判断是否为空(简化版)。

    isEmptySv([])  // true
  • isEqual(x, y) — 深度相等比较(支持 Date/RegExp)。

    isEqual({ a: 1 }, { a: 1 })  // true
  • isHexColor(str) — 判断是否为十六进制颜色。

    isHexColor('#fff')  // true
  • isValidEmail(email) — 判断是否为有效邮箱。

    isValidEmail('[email protected]')  // true
  • isPC() — 判断是否为浏览器环境。

    isPC()  // true
  • isWindow(val) — 判断是否为 window 对象。

    isWindow(window)  // true
  • isElement(val) — 判断是否为 DOM 元素。

    isElement(document.body)  // true
  • isIOS() — 判断设备是否为 iOS。

    isIOS()  // true

日期时间格式化 — format

  • formatFull(date) — 完整日期时间(斜杠分隔)。

    formatFull(new Date())  // "2026/06/03 14:30:45"
  • formatFullReplace(date) — 完整日期时间(短横线分隔)。

    formatFullReplace(new Date())  // "2026-06-03 14:30:45"
  • formatYMD(date) — 中文年月日。

    formatYMD(new Date())  // "2026年6月3日"
  • formatWeek(date) — 星期几。

    formatWeek(new Date())  // "星期三"

数字与货币格式化 — format

  • formatRmb(value, options) — 货币格式化(人民币)。

    formatRmb(1234.56, { type: 'zh-CN', currency: 'CNY' })  // "¥1,234.56"
  • formatNum(value) — 千位分隔符。

    formatNum(1234567)  // "1,234,567"
  • percentCN(value, digit) — 百分比格式化。

    percentCN(0.1234, 2)  // "12.34%"
  • compactEN(value) — 大数简化(英文缩写)。

    compactEN(12345)  // "12K"
  • compactCN(value) — 大数简化(中文缩写)。

    compactCN(12345)  // "1.2万"
  • signed(value, digit) — 带正负号显示。

    signed(42, 1)  // "+42.0"

字符串处理 — format

  • maskPhone(phone) — 手机号脱敏(隐藏中间4位)。

    maskPhone('13812345678')  // "138****5678"
  • spacePhone(phone) — 手机号空格分隔。

    spacePhone('13812345678')  // "138 1234 5678"
  • capitalize(str) — 每个单词首字母大写。

    capitalize('hello world')  // "Hello World"
  • kebabToCamel(str) — 短横线转小驼峰。

    kebabToCamel('hello-world')  // "helloWorld"
  • camelToKebab(str) — 驼峰转短横线。

    camelToKebab('helloWorld')  // "hello-world"
  • toCamel(str) — 下划线转驼峰。

    toCamel('hello_world')  // "helloWorld"
  • firstUpper(str) — 首字母大写。

    firstUpper('hello')  // "Hello"
  • firstLower(str) — 首字母小写。

    firstLower('Hello')  // "hello"
  • reverse(str) — 反转字符串。

    reverse('hello')  // "olleh"
  • trimAll(str) — 去除所有空格。

    trimAll(' h e l lo ')  // "hello"
  • truncate(str, max, suffix?) — 超长文本截断。

    truncate('Hello World', 8)  // "Hello..."
  • truncateByWords(str, max, suffix?) — 按字数截断(中文友好)。

    truncateByWords('你好世界欢迎你', 4)  // "你好世界..."

存储 — storage

  • localGet<T>(key) — 获取 localStorage(自动 JSON 解析)。

    localGet('user')  // { name: '张三' }
  • localSet(key, value) — 设置 localStorage(自动 JSON 序列化)。

    localSet('user', { name: '张三' })
  • localRm(key) — 移除指定 localStorage。

    localRm('user')
  • localClear() — 清除所有 localStorage。

    localClear()

拷贝 — copy

  • deepClone(obj) — 递归深拷贝(支持 Date/RegExp/Map/Set/循环引用)。

    deepClone({ a: 1, b: { c: 2 } })
  • deepCloneWithJSON(obj) — JSON 深拷贝(仅 JSON 安全类型)。

    deepCloneWithJSON({ a: 1 })
  • shallowClone(obj) — 浅拷贝(仅第一层)。

    shallowClone({ a: 1, b: { c: 2 } })

数组 — array

  • unique(arr) — Set 去重。

    unique([1, 2, 2, 3])  // [1, 2, 3]
  • uniqueByKey(arr, key) — 对象数组按 key 去重。

    uniqueByKey([{ id: 1 }, { id: 1 }], 'id')
  • sortNumAsc(arr) — 数值升序。

    sortNumAsc([3, 1, 2])  // [1, 2, 3]
  • sortNumDesc(arr) — 数值降序。

    sortNumDesc([1, 3, 2])  // [3, 2, 1]
  • sortByKey(arr, key, order?) — 按对象属性排序。

    sortByKey([{ age: 30 }, { age: 20 }], 'age')
  • toArray(arrayLike) — 类数组转数组。

    toArray(document.querySelectorAll('div'))
  • mergeArrays(...arrays) — 合并多个数组。

    mergeArrays([1, 2], [3, 4], [5])  // [1, 2, 3, 4, 5]
  • flatten(arr, depth?) — 多维数组扁平化到指定层级(默认 1 层,传 Infinity 完全展开)。

    flatten([1, [2, [3, 4]], 5])          // [1, 2, [3, 4], 5]
    flatten([1, [2, [3, 4]], 5], Infinity) // [1, 2, 3, 4, 5]
  • arrFind(arr, key, value) — 对象数组中按 key-value 查找第一个匹配项。

    arrFind([{ id: 1 }, { id: 2 }], 'id', 2)  // { id: 2 }
  • groupBy(arr, key) — 对象数组按指定属性分组。

    groupBy([{ type: 'fruit' }, { type: 'vegetable' }], 'type')
    // => { fruit: [...], vegetable: [...] }
  • filterEmptyValues(obj) — 移除对象中值为空(null / undefined / 空字符串)的属性。

    filterEmptyValues({ a: 1, b: '', c: null })  // { a: 1 }
  • createRange(length, mapFn?) — 快速生成范围数组。

    createRange(5)  // [0, 1, 2, 3, 4]
    createRange(3, (i) => i * 2)  // [0, 2, 4]

Cookie — cookie

  • setCookie(name, value, days?) — 设置 Cookie(默认7天)。

    setCookie('token', 'abc123', 30)
  • getCookie(name) — 获取 Cookie。

    getCookie('token')  // "abc123"
  • delCookie(name) — 删除 Cookie。

    delCookie('token')

浏览器工具 — browser

URL 参数

  • getUrlParams(url?) — 获取 URL 参数对象。

    getUrlParams('?a=1&b=2')  // { a: '1', b: '2' }
  • getUrlParam(key, url?) — 获取单个 URL 参数。

    getUrlParam('a')  // "1"
  • toQueryString(params) — 对象转 URL 参数字符串。

    toQueryString({ a: 1, b: 'hello' })  // "a=1&b=hello"

剪贴板与文件

  • copyToClipboard(text) — 复制文本到剪贴板(支持降级)。

    await copyToClipboard('Hello')
  • downloadFile(content, filename, mimeType?) — 下载文件(Blob)。

    downloadFile('Hello', 'hello.txt')
  • exportJSON(data, filename?) — 导出 JSON 为文件。

    exportJSON({ name: '张三' })

页面滚动

  • scrollToTop(behavior?) — 滚动到顶部(默认平滑)。

    scrollToTop()
  • scrollToBottom(behavior?) — 滚动到底部(默认平滑)。

    scrollToBottom()
  • onScroll(callback) — 监听滚动(rAF 节流),返回清理函数。

    const off = onScroll(y => console.log(y))

可视区域检测

  • observeIntersection(target, onEnter, onLeave?, options?) — 监听元素进入/离开可视区域,返回清理函数。

    const cleanup = observeIntersection(
      document.querySelector('.footer')!,
      () => loadMore(10),
    );

防抖与节流 — control

  • debounce(fn, delay?, options?) — 防抖,停止调用 delay 毫秒后才执行。

    const fn = debounce((val: string) => console.log(val), 500)
    fn('a'); fn('b'); fn('c')
    // => 'c'
  • throttle(fn, interval?, options?) — 节流,固定间隔内最多执行一次。

    const fn = throttle((val: string) => console.log(val), 500)
    fn('a'); fn('b'); fn('c')
    // => 'a',500ms 后输出 'c'