Skip to content

工具函数参考 ​

@jiess/utils 提供了 31 个以 $ 前缀命名的工具函数,按功能分为以下类别。

格式速查 ​

日期格式码 ​

码含义示例输出
yyyy / YYYY四位年份2023
yy两位年份23
MM月份(大写=月)01~12
dd / DD日期(大写/小写均可)01~31
HH24小时制(大写=时)00~23
hh12小时制(小写=时)01~12
mm分钟(小写=分)00~59
ss秒00~59
SSS / S毫秒000~999
qq季度01~04

注意:MM 是月份,mm 是分钟;HH 是 24 小时制,hh 是 12 小时制。yyyy 和 YYYY 等效,dd 和 DD 等效。

$check 支持的类型字符串 ​

string, number, boolean, array, object, function, symbol, bigint, null, undefined, regexp/regex/exp, date, promise, error


一、类型判断 ​

$check(value, type, state?) ​

精确的类型检查,同时作为 TypeScript 类型守卫。

参数类型必填说明
valueany✅待检查的值
typestring | string[]✅期望类型,大小写不敏感,支持数组
stateboolean❌默认 true,false 时不抛异常,直接返回 false

返回:boolean,同时触发 TypeScript 类型收窄。

typescript
// —— 基本用法 ——
$check('hello', 'string')    // true
$check(123, 'number')        // true
$check([], 'array')          // true
$check(null, 'null')         // true

// —— 类型守卫 ——
if ($check(value, 'string')) {
  // 此处 TypeScript 自动将 value 收窄为 string
  value.toUpperCase()
}

// —— 数组匹配(满足其一即可) ——
if ($check(value, ['string', 'number'])) {
  // value 被收窄为 string | number
}

// —— 支持特殊类型 ——
$check(new Date(), 'Date')           // true
$check(/regex/, 'exp')               // true(大小写不敏感)
$check(Symbol('x'), 'Symbol')        // true
$check(BigInt(1), 'BigInt')          // true

// —— state 参数控制 ——
$check('hello', 123 as any, false)   // false,不抛异常
$check('hello', 123 as any, true)    // 抛出异常

$identify(value, type, state?) ​

与 $check 完全相同(export const $identify = $check),两个名称可互换使用。


二、对象操作 ​

$diff(a, b, isClone?) ​

深度比较两个值是否相等,正确处理循环引用。

参数类型必填说明
aany✅第一个待比较值
bany✅第二个待比较值
isCloneboolean❌默认 true;false 时跳过克隆步骤直接深度比较(非浅引用比较)
typescript
$diff({ a: 1, b: { c: 2 } }, { a: 1, b: { c: 2 } })  // true
$diff(1, '1')      // false
$diff(NaN, NaN)     // true(NaN 特殊处理)

// 循环引用
const a: any = {}, b: any = {}
a.self = a; b.self = b
$diff(a, b)         // true

支持的特殊类型:除普通对象/数组外,$diff 还能正确比较 Date、RegExp、Map、Set、ArrayBuffer/SharedArrayBuffer、TypedArray、BigInt、Symbol、Function(按字符串形式比较)。Promise 始终按引用判定(不同 Promise 实例即使内容相同也返回 false)。

$clone(target, custom?, seen?) ​

深度克隆,支持循环引用、Symbol 键、Date/RegExp/BigInt。

参数类型必填说明
targetany✅被克隆对象
custom(val, type) => any❌自定义处理回调;type 为 'filter' 时在克隆各属性值阶段调用(返回非 undefined 则替换该值,返回 undefined 则跳过该属性),type 为 'clone' 时在整棵树克隆完成后对结果调用(返回非 undefined 则替换最终结果)
seenWeakMap❌内部使用,用于防止循环引用无限递归
typescript
const obj = { a: 1, b: { c: 2 } }
const cloned = $clone(obj)
cloned.b !== obj.b   // 深克隆,内部引用不等

// 循环引用
const self: any = { a: 1 }
self.myself = self
const cl = $clone(self)
cl.myself === cl     // true,循环关系被保持

// 自定义处理
const cl2 = $clone({ fn: () => {} }, (val, type) => {
  return type === 'filter' && $check(val, 'function') ? '[函数]' : val
})
// cl2.fn === '[函数]'

注意:带 JIESS_TAG 标记的 Jiess 内部对象不会被深度克隆,而是传递引用。

$copy(obj_new, obj_old) ​

将旧对象的所有属性深度拷贝到新实例,用于从模板对象生成新对象。

参数类型必填说明
obj_newobject✅新对象(就地修改)
obj_oldobject✅旧对象
typescript
const template = { a: 1, b: { c: 2 } }
const instance = {}
$copy(instance, template)
// instance = { a: 1, b: { c: 2 } }
// instance.b !== template.b(深拷贝)

与 $clone 的区别:$clone 返回新对象,$copy 将旧属性写入已有对象。

$deepMerge(target, source) ​

深度合并,仅当 source 属性为"纯粹对象"时才递归合并,其他类型直接覆盖。

参数类型必填说明
targetobject✅目标对象(就地修改)
sourceobject✅源对象
typescript
const t = { a: 1, b: { x: 1 } }
$deepMerge(t, { b: { y: 2 }, c: 3 })
// t = { a: 1, b: { x: 1, y: 2 }, c: 3 }

// 数组:直接覆盖,不做合并
const t2 = { arr: [1, 2] }
$deepMerge(t2, { arr: [3, 4] })
// t2.arr = [3, 4](非合并结果)

三、路径操作 ​

$getByPath(obj, path) ​

按点分隔路径安全读取深层属性,路径不存在时返回 undefined 而非报错。

参数类型必填说明
objobject✅目标对象
pathstring | (string|number)[]✅'a.b.c'、'a[0].b' 或 ['a', 0, 'b']
typescript
const data = { user: { profile: { name: '张三' } } }

$getByPath(data, 'user.profile.name')            // '张三'
$getByPath(data, ['user', 'profile', 'name'])   // '张三'
$getByPath(data, 'user.profile.missing')         // undefined(不报错)
$getByPath(data, '')                             // undefined(空路径返回 undefined)

$setByPath(obj, path, value) ​

按路径写入值,中间的路径会自动创建对象/数组。

参数类型必填说明
objobject✅目标对象(就地修改)
pathstring✅点分隔路径字符串
valueany✅待写入值
typescript
const obj: any = {}
$setByPath(obj, 'a.b.c', 'hello')
// obj = { a: { b: { c: 'hello' } } }

// 数组索引格式:路径中 [n] 会被解析为数字索引,自动创建数组
$setByPath(obj, 'list[0].name', '张三')
// obj.list = [{ name: '张三' }]

// a[] 推送语法:路径以 [] 结尾时,将 value 追加到目标数组末尾(数组不存在则自动创建)
$setByPath(obj, 'tags[]', 'a')
$setByPath(obj, 'tags[]', 'b')
// obj.tags = ['a', 'b']

四、日期与时间 ​

$dateFormat(date, fmt) ​

将 Date 对象(或时间戳、日期字符串)按格式字符串输出。

参数类型必填说明
dateDate | number | string✅日期数据
fmtstring✅格式字符串(见 格式速查)
typescript
const d = new Date('2023-06-15T14:30:45.123')

$dateFormat(d, 'yyyy-MM-dd')              // '2023-06-15'
$dateFormat(d, 'yyyy-MM-dd HH:mm:ss')     // '2023-06-15 14:30:45'
$dateFormat(d, 'yyyy年MM月dd日 HH时mm分ss秒') // '2023年06月15日 14时30分45秒'
$dateFormat(d, 'yyyy-MM-dd qq')           // '2023-06-15 02'(Q2 季度)
$dateFormat(d, 'HH:mm:ss.SSS')            // '14:30:45.123'
$dateFormat(d, '')                        // ''

$timer(fn?, wait?) ​

一次性延迟执行的回调,执行后自动清除,无返回值、外部无法取消。

参数类型必填默认值说明
fnFunction❌() => {}回调函数
waitnumber❌0等待毫秒数
typescript
$timer(() => {
  console.log('2秒后执行')
}, 2000)
// 2 秒后打印,无需手动 clearTimeout

五、防抖与节流 ​

工厂函数与实例函数 ​

函数模式首次执行说明
$debounce1(fn, wait)防抖延迟高频触发结束后等待 wait 再执行
$debounce2(fn, wait)防抖延迟同 $debounce1,始终清除旧计时器重新计时
$throttle1(fn, wait)节流-计时器延迟每隔 wait 执行一次,首次等待 wait 后执行
$throttle2(fn, wait)节流-时间戳立即每隔 wait 执行一次,首次立即执行
工厂说明
$baseDebounce1(callback1?, immediate?)创建带预置回调的防抖工厂
$baseDebounce2(callback1?)同上,$debounce2 的工厂版本
$baseThrottle1(callback1?)创建带预置回调的节流工厂
$baseThrottle2(callback1?)同上,$throttle2 的工厂版本
typescript
// —— 搜索输入防抖 ——
const onInput = (val: string) => {
  $debounce1(() => fetch(`/search?q=${val}`), 300)
}

// —— 滚动事件节流 ——
window.addEventListener('scroll', () => {
  $throttle1(() => updateScrollUI(window.scrollY), 100)
})

// —— 防抖对比:$debounce1 vs $debounce2 ——
// 用户快速输入 "abc",300ms 间隔:
// $debounce1 → 执行 1 次(输入结束 300ms 后,同 $debounce2)
// $debounce2 → 执行 1 次(同 $debounce1,两者均延迟执行)
// 区别:$debounce1 的 $baseDebounce1 支持 immediate 参数,$debounce2 无此选项

// —— 节流对比:$throttle1 vs $throttle2 ——
// 快速连续触发 10 次,间隔 50ms,wait=100ms:
// $throttle1 → 执行多次(首次等待 100ms,之后每次间隔 100ms)
// $throttle2 → 执行多次(首次立即执行,之后每次间隔 100ms)

$microDebounce(fn) ​

基于 Promise.resolve().then() 的微任务防抖。调用 $microDebounce() 返回一个防抖函数,同一个防抖实例在微任务队列中最多存在一个待执行函数。

typescript
const microDebounce = $microDebounce()

microDebounce(() => console.log('A'))
microDebounce(() => console.log('B'))  // A 被 B 覆盖
// 当前事件循环结束后仅输出 "B"

// 每次调用 $microDebounce() 创建独立实例,彼此不共享 pending 状态

六、Cookie 操作 ​

$getCookie(name) ​

读取指定名称的 cookie,name 参数已做正则转义,可安全使用。

参数类型必填说明
namestring✅cookie 名称

DOM 不可用时返回 null,无需环境检测。

typescript
const token = $getCookie('auth_token')
if (token) {
  fetch('/api/profile', { headers: { Authorization: `Bearer ${token}` } })
}

$setCookie(name, value, Days?) ​

写入 cookie,value 自动 encodeURIComponent。

参数类型必填默认值说明
namestring✅—cookie 名称
valuestring✅—cookie 值(自动编码)
Daysnumber❌30过期天数;0 = 当天过期(session);负数 = 立即过期
typescript
$setCookie('theme', 'dark')           // 30 天后过期
$setCookie('token', jwt, 7)          // 7 天后过期
$setCookie('temp', 'data', 0)        // 会话级别

// 清除 cookie
$setCookie('old_key', '', -1)

七、URL 参数 ​

$querystring ​

提供 stringify 和 parse 两个方法。

typescript
// stringify(obj) → 对象 → 查询字符串
$querystring.stringify({ name: '张三', age: 30, tags: ['a', 'b'] })
// "name=张三&age=30&tags=a&tags=b"

// parse(str) → 查询字符串 → 对象
$querystring.parse('name=张三&age=30&tags=a&tags=b')
// { name: '张三', age: '30', tags: ['a', 'b'] }
// 同名 key 自动聚合成数组

// 高级用法:构建带参数的 API URL
function buildUrl(path: string, params: Record<string, unknown>) {
  const qs = $querystring.stringify(params)
  return qs ? `${path}?${qs}` : path
}
buildUrl('/api/users', { page: 1, size: 20 })  // "/api/users?page=1&size=20"

八、其他工具 ​

$getUUID(len?) ​

生成随机字符串(非加密安全,勿用于密码学场景)。

参数类型必填默认值说明
lennumber❌32返回长度。0 返回空字符串
typescript
$getUUID()      // 32 位随机字符串:"a1b2c3d4..."
$getUUID(8)     // 8 位随机字符串

$isDef(value) / $isUndef(value, b?) ​

判断值是否"有定义" / "无定义"。默认仅 null、undefined、NaN 视为无定义;b=true 时额外将空字符串 "" 也视为无定义。

参数类型必填默认值说明
valueany✅—被检查的值
bboolean❌—为 true 时将空字符串也视为无定义
typescript
$isUndef(null)      // true
$isUndef(undefined) // true
$isUndef(NaN)       // true
$isUndef(0)         // false(0 也算是"有定义"的值)
$isUndef('')        // false(默认空字符串视为有定义)
$isUndef('', true)  // true(b=true 时空字符串也视为无定义)

$isDef('hello')     // true
$isDef(null)        // false

$firstUpperCase(str) / $firstLowerCase(str) ​

只转换首字母的大小写,其余字符不变。前导空白会被保留;非字符串类型原样返回;空字符串返回空字符串。

typescript
$firstUpperCase('hello')   // 'Hello'
$firstLowerCase('Hello')   // 'hello'
$firstUpperCase('')        // ''
$firstUpperCase('  a')     // '  A'(前导空白保留)
$firstUpperCase(123)       // 123(非字符串原样返回)

$nfn(..._) ​

空操作函数,用作默认回调占位符。接收任意参数,无返回值。

typescript
const options = {
  onSuccess: userCallback || $nfn,
  onError: errorCallback || $nfn
}

$initExecute(ctx, ...args1) ​

返回一个执行器函数,可用于延迟调用。返回的执行器每次被调用时都会执行传入的 func,不做结果缓存。

typescript
// 返回的执行器可以多次调用不同的 func
const exec = $initExecute('prefix')

exec((prefix, extra) => `${prefix}_${extra}`, ['suffix'])
// 'prefix_suffix'(不缓存,每次调用都重新执行)

### `$canUseDom`

编译时常量 `boolean`,判断是否处于浏览器环境(`window` 和 `document` 是否可用)。

```typescript
if ($canUseDom) {
  // 安全操作 DOM
  document.addEventListener('DOMContentLoaded', init)
} else {
  // SSR / Node.js 环境
}

$serializeObject(obj) ​

对象序列化,支持 Jiess 内部对象类型(Date、RegExp、Map、Set、模板对象等)的特殊处理。

值类型序列化结果
Date'Date: ISO字符串'
RegExp'RegExp: /pattern/flags'
Map'Map: [[k,v],...]'
Set'Set: [v,...]'
模板对象($model=template)'Template: name' 或 JSON
普通对象紧凑 JSON

边界情况速查 ​

函数边界行为
$diffNaN === NaN → true;isClone=false 时跳过克隆但仍为深度比较;isClone=true 时带 JIESS_TAG/isNotClone 标记的对象不克隆、传递引用参与比较
$clone带 JIESS_TAG 的内部对象传递引用;seen WeakMap 防递归
$deepMerge数组和特殊对象直接替换,不做合并;undefined 值会覆盖 target
$check'array' 用 Array.isArray;type 为数组时批量匹配
$dateFormat无效格式中的字符 d 会被日期值替换(如 'invalid' → 'invali1')
$getUUID基于 Math.random(),非加密安全,勿用于 token 生成
$microDebounce返回 Promise,但无 async 标记时返回值是同步链
$getByPathpath='' 返回 undefined(而非 obj 自身);多段中间为 undefined 时整体返回 undefined
$setByPath中间路径自动创建,数组索引需用数字
$timer内部 clearTimeout,外部无法取消