@jiakun-zhao/utils 1.4.2 → 1.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,10 +1,44 @@
1
1
  //#region src/addons/assert.ts
2
+ /**
3
+ * 断言函数,当条件为 false 时抛出错误
4
+ * @param condition - 断言条件
5
+ * @param message - 错误信息
6
+ * @example
7
+ * ```ts
8
+ * assert(true, '不会抛出错误') // 正常执行
9
+ * assert(false, '会抛出错误') // 抛出 Error: 会抛出错误
10
+ * ```
11
+ */
2
12
  function assert(condition, message) {
3
13
  if (!condition) throw new Error(message);
4
14
  }
5
15
 
6
16
  //#endregion
7
17
  //#region src/addons/deep-equal.ts
18
+ /**
19
+ * 深度比较两个值是否相等
20
+ * 支持 Array、Object、RegExp、Date 等类型的比较
21
+ * @param a - 第一个值
22
+ * @param b - 第二个值
23
+ * @returns 是否深度相等
24
+ * @example
25
+ * ```ts
26
+ * isDeepEqual(1, 1) // true
27
+ * isDeepEqual({}, {}) // true
28
+ * isDeepEqual('foo', 'foo') // true
29
+ * isDeepEqual([1, 2, 3], [1, 2, 3]) // true
30
+ * isDeepEqual(isDeepEqual, isDeepEqual) // true
31
+ * isDeepEqual(/foo/, /foo/) // true
32
+ * isDeepEqual(null, null) // true
33
+ * isDeepEqual(Number.NaN, Number.NaN) // true
34
+ * isDeepEqual([], []) // true
35
+ * isDeepEqual([{ a: 1 }, [{ b: { c: [1] } }]], [{ a: 1 }, [{ b: { c: [1] } }]]) // true
36
+ * isDeepEqual(1, '1') // false
37
+ * isDeepEqual(null, undefined) // false
38
+ * isDeepEqual({ a: 1, b: [2, 3] }, { a: 1, b: [2, 5] }) // false
39
+ * isDeepEqual(/foo/i, /bar/g) // false
40
+ * ```
41
+ */
8
42
  function isDeepEqual(a, b) {
9
43
  if (a === b) return true;
10
44
  const constructor = a?.constructor;
@@ -22,6 +56,17 @@ function isDeepEqual(a, b) {
22
56
 
23
57
  //#endregion
24
58
  //#region src/addons/http-status-code.ts
59
+ /**
60
+ * HTTP 状态码及其对应的描述信息
61
+ * 包含了所有标准的 HTTP 状态码
62
+ * @example
63
+ * ```ts
64
+ * status[200] // 'OK'
65
+ * status[404] // 'Not Found'
66
+ * status[500] // 'Internal Server Error'
67
+ * status[418] // "I'm a Teapot"
68
+ * ```
69
+ */
25
70
  const status = {
26
71
  100: "Continue",
27
72
  101: "Switching Protocols",
@@ -87,12 +132,53 @@ const status = {
87
132
  510: "Not Extended",
88
133
  511: "Network Authentication Required"
89
134
  };
135
+ /**
136
+ * 根据 HTTP 状态码获取对应的描述信息
137
+ * @param code - HTTP 状态码
138
+ * @returns 状态码描述
139
+ * @example
140
+ * ```ts
141
+ * getHttpStatusMessage(200) // 'OK'
142
+ * getHttpStatusMessage(404) // 'Not Found'
143
+ * getHttpStatusMessage(500) // 'Internal Server Error'
144
+ * getHttpStatusMessage(418) // "I'm a Teapot"
145
+ * ```
146
+ */
90
147
  function getHttpStatusMessage(code) {
91
148
  return status[code];
92
149
  }
93
150
 
94
151
  //#endregion
95
152
  //#region src/addons/natural-compare.ts
153
+ /**
154
+ * 自然排序比较函数,按自然语言顺序比较字符串或数字
155
+ * 类似文件名排序,"file2" < "file10"
156
+ * @param a - 第一个值
157
+ * @param b - 第二个值
158
+ * @returns 比较结果:-1 表示 a < b,0 表示 a = b,1 表示 a > b
159
+ * @example
160
+ * ```ts
161
+ * naturalCompare(1, 2) // -1
162
+ * naturalCompare(2, 1) // 1
163
+ * naturalCompare(1, 1) // 0
164
+ *
165
+ * naturalCompare('a', 'b') // -1
166
+ * naturalCompare('b', 'a') // 1
167
+ * naturalCompare('a', 'a') // 0
168
+ *
169
+ * // 数字字符串按数值大小排序,而不是字典序
170
+ * naturalCompare('file1', 'file2') // -1
171
+ * naturalCompare('file2', 'file10') // -1 (2 < 10 自然顺序)
172
+ * naturalCompare('file10', 'file2') // 1
173
+ *
174
+ * // 用于数组排序
175
+ * ['file10.txt', 'file2.txt', 'file1.txt'].sort(naturalCompare) // ['file1.txt', 'file2.txt', 'file10.txt']
176
+ *
177
+ * // 版本号比较
178
+ * naturalCompare('v1.0.1', 'v1.0.10') // -1
179
+ * naturalCompare('v1.0.10', 'v1.0.2') // 1
180
+ * ```
181
+ */
96
182
  function naturalCompare(a, b) {
97
183
  var i, codeA, codeB = 1, posA = 0, posB = 0, alphabet = String.alphabet;
98
184
  function getCode(str, pos, code) {
@@ -118,13 +204,84 @@ function naturalCompare(a, b) {
118
204
 
119
205
  //#endregion
120
206
  //#region src/base/array.ts
207
+ /**
208
+ * 判断值是否为数组
209
+ * @param val - 要判断的值
210
+ * @returns 是否为数组
211
+ * @example
212
+ * ```ts
213
+ * isArray([]) // true
214
+ * isArray([1, 2, 3]) // true
215
+ * isArray('') // false
216
+ * isArray(null) // false
217
+ * ```
218
+ */
121
219
  const isArray = (val) => Array.isArray(val);
220
+ /**
221
+ * 将值转换为数组,如果已经是数组则返回原数组
222
+ * @param val - 要转换的值
223
+ * @returns 数组
224
+ * @example
225
+ * ```ts
226
+ * toArray(1) // [1]
227
+ * toArray([1, 2, 3]) // [1, 2, 3]
228
+ * toArray('hello') // ['hello']
229
+ * toArray(null) // [null]
230
+ * ```
231
+ */
122
232
  const toArray = (val) => isArray(val) ? val : [val];
233
+ /**
234
+ * 数组去重
235
+ * @param arr - 输入数组
236
+ * @returns 去重后的数组
237
+ * @example
238
+ * ```ts
239
+ * uniq([1, 2, 2, 3, 3, 3]) // [1, 2, 3]
240
+ * uniq(['a', 'b', 'a', 'c']) // ['a', 'b', 'c']
241
+ * uniq([]) // []
242
+ * ```
243
+ */
123
244
  const uniq = (arr) => [...new Set(arr)];
245
+ /**
246
+ * 获取数组的单个元素,如果数组只有一个元素则返回该元素,否则返回 null
247
+ * @param arr - 输入数组
248
+ * @returns 单个元素或 null
249
+ * @example
250
+ * ```ts
251
+ * singleOrNull([1]) // 1
252
+ * singleOrNull(['only']) // 'only'
253
+ * singleOrNull([]) // null
254
+ * singleOrNull([1, 2, 3]) // null
255
+ * ```
256
+ */
124
257
  const singleOrNull = (arr) => arr.length === 1 ? arr[0] : null;
258
+ /**
259
+ * 创建指定长度的数组
260
+ * @param len - 数组长度
261
+ * @param mapFn - 映射函数,可选
262
+ * @returns 创建的数组
263
+ * @example
264
+ * ```ts
265
+ * createArray(3) // [0, 1, 2]
266
+ * createArray(3, (i) => i * 2) // [0, 2, 4]
267
+ * createArray(5, (i) => `item-${i}`) // ['item-0', 'item-1', 'item-2', 'item-3', 'item-4']
268
+ * createArray(0) // []
269
+ * ```
270
+ */
125
271
  function createArray(len, mapFn) {
126
272
  return Array.from({ length: len }, (_, index) => mapFn?.(index) ?? index);
127
273
  }
274
+ /**
275
+ * 随机打乱数组(会修改原数组)
276
+ * @param array - 要打乱的数组
277
+ * @returns 打乱后的数组
278
+ * @example
279
+ * ```ts
280
+ * const arr = [1, 2, 3, 4, 5]
281
+ * shuffle(arr) // [3, 1, 5, 2, 4] (随机顺序)
282
+ * // ⚠️ 原数组也会被修改
283
+ * ```
284
+ */
128
285
  function shuffle(array) {
129
286
  for (let i = array.length - 1; i > 0; i--) {
130
287
  const j = Math.floor(Math.random() * (i + 1));
@@ -132,6 +289,11 @@ function shuffle(array) {
132
289
  }
133
290
  return array;
134
291
  }
292
+ /**
293
+ * 生成数字范围序列
294
+ * @param args - 参数
295
+ * @returns 数字数组
296
+ */
135
297
  function range(...args) {
136
298
  if (args.length === 1) args.unshift(0);
137
299
  const [start, stop, step = 1] = args;
@@ -142,46 +304,352 @@ function range(...args) {
142
304
 
143
305
  //#endregion
144
306
  //#region src/base/boolean.ts
307
+ /**
308
+ * 判断值是否为布尔类型
309
+ * @param val - 要判断的值
310
+ * @returns 是否为布尔值
311
+ * @example
312
+ * ```ts
313
+ * isBoolean(true) // true
314
+ * isBoolean(false) // true
315
+ * isBoolean('true') // false
316
+ * isBoolean(1) // false
317
+ * isBoolean(null) // false
318
+ * ```
319
+ */
145
320
  const isBoolean = (val) => typeof val === "boolean";
146
321
 
147
322
  //#endregion
148
323
  //#region src/base/string.ts
324
+ /**
325
+ * 获取值的字符串表示形式
326
+ * @param val - 输入值
327
+ * @returns 字符串表示
328
+ * @example
329
+ * ```ts
330
+ * toString({}) // '[object Object]'
331
+ * toString([]) // '[object Array]'
332
+ * toString(null) // '[object Null]'
333
+ * toString(undefined) // '[object Undefined]'
334
+ * toString(123) // '[object Number]'
335
+ * ```
336
+ */
149
337
  const toString = (val) => Object.prototype.toString.call(val);
338
+ /**
339
+ * 判断值是否为字符串
340
+ * @param val - 要判断的值
341
+ * @returns 是否为字符串
342
+ * @example
343
+ * ```ts
344
+ * isString('hello') // true
345
+ * isString('') // true
346
+ * isString(123) // false
347
+ * isString(null) // false
348
+ * ```
349
+ */
150
350
  const isString = (val) => typeof val === "string";
151
- const slash = (str) => str.replace(/\\/g, "/");
351
+ /**
352
+ * 将反斜杠转换为正斜杠
353
+ * @param str - 输入字符串
354
+ * @returns 转换后的字符串
355
+ * @example
356
+ * ```ts
357
+ * slash('C:\\Users\\test') // 'C:/Users/test'
358
+ * slash('path\\to\\file') // 'path/to/file'
359
+ * slash('path/to/file') // 'path/to/file'
360
+ * ```
361
+ */
362
+ const slash = (str) => str.replace(/\\\\/g, "/");
363
+ /**
364
+ * 确保字符串以指定前缀开头
365
+ * @param str - 输入字符串
366
+ * @param prefix - 前缀
367
+ * @returns 处理后的字符串
368
+ * @example
369
+ * ```ts
370
+ * ensurePrefix('example.com', 'https://') // 'https://example.com'
371
+ * ensurePrefix('https://example.com', 'https://') // 'https://example.com'
372
+ * ensurePrefix('path', '/') // '/path'
373
+ * ```
374
+ */
152
375
  const ensurePrefix = (str, prefix) => str.startsWith(prefix) ? str : prefix + str;
376
+ /**
377
+ * 确保字符串以指定后缀结尾
378
+ * @param str - 输入字符串
379
+ * @param suffix - 后缀
380
+ * @returns 处理后的字符串
381
+ * @example
382
+ * ```ts
383
+ * ensureSuffix('file', '.json') // 'file.json'
384
+ * ensureSuffix('file.json', '.json') // 'file.json'
385
+ * ensureSuffix('path', '/') // 'path/'
386
+ * ```
387
+ */
153
388
  const ensureSuffix = (str, suffix) => str.endsWith(suffix) ? str : str + suffix;
389
+ /**
390
+ * 将字符串首字母大写,其余字母小写
391
+ * @param str - 输入字符串
392
+ * @returns 处理后的字符串
393
+ * @example
394
+ * ```ts
395
+ * capitalize('hello') // 'Hello'
396
+ * capitalize('HELLO') // 'Hello'
397
+ * capitalize('hELLO') // 'Hello'
398
+ * capitalize('hello world') // 'Hello world'
399
+ * // ⚠️ 空字符串会返回 'undefined'
400
+ * ```
401
+ */
154
402
  const capitalize = (str) => str[0].toUpperCase() + str.slice(1).toLowerCase();
155
403
 
156
404
  //#endregion
157
405
  //#region src/base/date.ts
406
+ /**
407
+ * 判断值是否为 Date 对象
408
+ * @param val - 要判断的值
409
+ * @returns 是否为 Date 对象
410
+ * @example
411
+ * ```ts
412
+ * isDate(new Date()) // true
413
+ * isDate(new Date('2024-01-01')) // true
414
+ * isDate('2024-01-01') // false
415
+ * isDate(null) // false
416
+ * ```
417
+ */
158
418
  const isDate = (val) => toString(val) === "[object Date]";
419
+ /**
420
+ * 获取当前时间戳(毫秒)
421
+ * @returns 时间戳
422
+ * @example
423
+ * ```ts
424
+ * timestamp() // 1705401600000
425
+ * ```
426
+ */
159
427
  const timestamp = () => +Date.now();
428
+ /**
429
+ * 判断日期是否为今天
430
+ * @param date - 要判断的日期
431
+ * @returns 是否为今天
432
+ * @example
433
+ * ```ts
434
+ * isToDay(new Date()) // true
435
+ * isToDay(new Date('2000-01-01')) // false
436
+ * ```
437
+ */
160
438
  const isToDay = (date) => isSameDay(date, /* @__PURE__ */ new Date());
439
+ /**
440
+ * 判断两个日期是否为同一天
441
+ * @param dateA - 第一个日期
442
+ * @param dateB - 第二个日期
443
+ * @returns 是否为同一天
444
+ * @example
445
+ * ```ts
446
+ * const date1 = new Date('2024-01-15T10:30:00')
447
+ * const date2 = new Date('2024-01-15T23:59:59')
448
+ * isSameDay(date1, date2) // true
449
+ * ```
450
+ * @example
451
+ * ```ts
452
+ * const date1 = new Date('2024-01-15')
453
+ * const date2 = new Date('2024-01-16')
454
+ * isSameDay(date1, date2) // false
455
+ * ```
456
+ */
161
457
  function isSameDay(dateA, dateB) {
162
458
  return dateA.getDate() === dateB.getDate() && dateA.getMonth() === dateB.getMonth() && dateA.getFullYear() === dateB.getFullYear();
163
459
  }
164
460
 
165
461
  //#endregion
166
462
  //#region src/base/function.ts
463
+ /**
464
+ * 判断值是否为函数
465
+ * @param val - 要判断的值
466
+ * @returns 是否为函数
467
+ * @example
468
+ * ```ts
469
+ * isFunction(() => {}) // true
470
+ * isFunction(function() {}) // true
471
+ * isFunction('function') // false
472
+ * isFunction(null) // false
473
+ * ```
474
+ */
167
475
  const isFunction = (val) => typeof val === "function";
476
+ /**
477
+ * 空函数,什么都不做
478
+ * @returns void
479
+ * @example
480
+ * ```ts
481
+ * const callback: Fn = noop // 作为默认回调
482
+ * callback() // 什么都不执行
483
+ * ```
484
+ */
168
485
  const noop = () => {};
486
+ /**
487
+ * 对值应用转换函数
488
+ * @param val - 输入值
489
+ * @param fn - 转换函数
490
+ * @returns 转换后的值
491
+ * @example
492
+ * ```ts
493
+ * transform(5, (x) => x * 2) // 10
494
+ * transform('hello', (s) => s.toUpperCase()) // 'HELLO'
495
+ * transform([1, 2, 3], (arr) => arr.length) // 3
496
+ * ```
497
+ */
169
498
  const transform = (val, fn) => fn(val);
170
499
 
171
500
  //#endregion
172
501
  //#region src/base/nullable.ts
502
+ /**
503
+ * 判断值是否为真值
504
+ * @param v - 要判断的值
505
+ * @returns 是否为真值
506
+ * @example
507
+ * ```ts
508
+ * isTruthy(true) // true
509
+ * isTruthy(1) // true
510
+ * isTruthy('hello') // true
511
+ * isTruthy({}) // true
512
+ * isTruthy([]) // true
513
+ * isTruthy(false) // false
514
+ * isTruthy(0) // false
515
+ * isTruthy('') // false
516
+ * isTruthy(null) // false
517
+ * isTruthy(undefined) // false
518
+ * ```
519
+ */
173
520
  const isTruthy = (v) => Boolean(v);
521
+ /**
522
+ * 判断值是否为 undefined
523
+ * @param val - 要判断的值
524
+ * @returns 是否为 undefined
525
+ * @example
526
+ * ```ts
527
+ * isUndefined(undefined) // true
528
+ * isUndefined(void 0) // true
529
+ * isUndefined(null) // false
530
+ * isUndefined('') // false
531
+ * ```
532
+ */
174
533
  const isUndefined = (val) => toString(val) === "[object Undefined]";
534
+ /**
535
+ * 判断值是否不为 undefined
536
+ * @param v - 要判断的值
537
+ * @returns 是否不为 undefined
538
+ * @example
539
+ * ```ts
540
+ * notUndefined('hello') // true
541
+ * notUndefined(0) // true
542
+ * notUndefined(null) // true
543
+ * notUndefined(undefined) // false
544
+ * ```
545
+ */
175
546
  const notUndefined = (v) => v !== void 0;
547
+ /**
548
+ * 判断值是否为 null
549
+ * @param val - 要判断的值
550
+ * @returns 是否为 null
551
+ * @example
552
+ * ```ts
553
+ * isNull(null) // true
554
+ * isNull(undefined) // false
555
+ * isNull('') // false
556
+ * isNull(0) // false
557
+ * ```
558
+ */
176
559
  const isNull = (val) => toString(val) === "[object Null]";
560
+ /**
561
+ * 判断值是否不为 null
562
+ * @param v - 要判断的值
563
+ * @returns 是否不为 null
564
+ * @example
565
+ * ```ts
566
+ * notNull('hello') // true
567
+ * notNull(0) // true
568
+ * notNull(undefined) // true
569
+ * notNull(null) // false
570
+ * ```
571
+ */
177
572
  const notNull = (v) => v !== null;
573
+ /**
574
+ * 判断值是否不为 null 且不为 undefined
575
+ * @param v - 要判断的值
576
+ * @returns 是否为非空值
577
+ * @example
578
+ * ```ts
579
+ * notNullish('hello') // true
580
+ * notNullish(0) // true
581
+ * notNullish(false) // true
582
+ * notNullish(null) // false
583
+ * notNullish(undefined) // false
584
+ * ```
585
+ */
178
586
  const notNullish = (v) => v != null;
587
+ /**
588
+ * 判断值是否已定义(不是 undefined)
589
+ * @param val - 要判断的值
590
+ * @returns 是否已定义
591
+ * @example
592
+ * ```ts
593
+ * isDefined('hello') // true
594
+ * isDefined(0) // true
595
+ * isDefined(null) // true
596
+ * isDefined(false) // true
597
+ * isDefined(undefined) // false
598
+ * ```
599
+ */
179
600
  const isDefined = (val) => typeof val !== "undefined";
180
601
 
181
602
  //#endregion
182
603
  //#region src/base/number.ts
604
+ /**
605
+ * 判断值是否为数字类型
606
+ * @param val - 要判断的值
607
+ * @returns 是否为数字
608
+ * @example
609
+ * ```ts
610
+ * isNumber(0) // true
611
+ * isNumber(1) // true
612
+ * isNumber(1.5) // true
613
+ * isNumber(Number.NaN) // true
614
+ * isNumber(Number.POSITIVE_INFINITY) // true
615
+ * isNumber('123') // false
616
+ * isNumber(null) // false
617
+ * ```
618
+ */
183
619
  const isNumber = (val) => typeof val === "number";
620
+ /**
621
+ * 将值限制在指定范围内
622
+ * @param n - 要限制的值
623
+ * @param min - 最小值
624
+ * @param max - 最大值
625
+ * @returns 限制后的值
626
+ * @example
627
+ * ```ts
628
+ * clamp(5, 0, 10) // 5 (在范围内)
629
+ * clamp(-5, 0, 10) // 0 (小于最小值,返回最小值)
630
+ * clamp(15, 0, 10) // 10 (大于最大值,返回最大值)
631
+ * clamp(1.5, 0, 1) // 1
632
+ * clamp(0.5, 0, 1) // 0.5
633
+ * ```
634
+ */
184
635
  const clamp = (n, min, max) => Math.min(max, Math.max(min, n));
636
+ /**
637
+ * 线性插值,返回两个值之间的插值
638
+ * @param min - 起始值
639
+ * @param max - 结束值
640
+ * @param t - 插值参数(0-1 之间)
641
+ * @returns 插值结果
642
+ * @example
643
+ * ```ts
644
+ * lerp(0, 100, 0.5) // 50 (中点)
645
+ * lerp(0, 100, 0) // 0 (起始点)
646
+ * lerp(0, 100, 1) // 100 (结束点)
647
+ * lerp(0, 100, -0.5) // 0 (t 被限制到 0)
648
+ * lerp(0, 100, 1.5) // 100 (t 被限制到 1)
649
+ * lerp(-100, 0, 0.5) // -50
650
+ * lerp(0, 10, 0.25) // 2.5
651
+ * ```
652
+ */
185
653
  function lerp(min, max, t) {
186
654
  const interpolation = clamp(t, 0, 1);
187
655
  return min + (max - min) * interpolation;
@@ -189,23 +657,112 @@ function lerp(min, max, t) {
189
657
 
190
658
  //#endregion
191
659
  //#region src/base/object.ts
660
+ /**
661
+ * 判断值是否为普通对象
662
+ * @param val - 要判断的值
663
+ * @returns 是否为对象
664
+ * @example
665
+ * ```ts
666
+ * isObject({}) // true
667
+ * isObject({ a: 1 }) // true
668
+ * isObject([]) // false
669
+ * isObject(null) // false
670
+ * isObject(new Date()) // false
671
+ * ```
672
+ */
192
673
  const isObject = (val) => toString(val) === "[object Object]";
674
+ /**
675
+ * 判断键是否为对象的键
676
+ * @param val - 对象
677
+ * @param key - 键
678
+ * @returns 是否为对象的键
679
+ * @example
680
+ * ```ts
681
+ * const obj = { a: 1, b: 2, c: 3 }
682
+ * isKeyOf(obj, 'a') // true
683
+ * isKeyOf(obj, 'b') // true
684
+ * isKeyOf(obj, 'd') // false
685
+ * // 注意:isKeyOf 使用 'key in val',所以继承属性也会返回 true
686
+ * isKeyOf(obj, 'toString') // true
687
+ * ```
688
+ */
193
689
  const isKeyOf = (val, key) => key in val;
690
+ /**
691
+ * 根据条件过滤对象的属性
692
+ * @param obj - 输入对象
693
+ * @param fn - 过滤函数
694
+ * @returns 过滤后的对象
695
+ * @example
696
+ * ```ts
697
+ * const obj = { a: 1, b: 2, c: 3, d: 4 }
698
+ * objectFilter(obj, (key, value) => value > 2) // { c: 3, d: 4 }
699
+ * objectFilter(obj, (key, value) => key === 'a') // { a: 1 }
700
+ * ```
701
+ */
194
702
  function objectFilter(obj, fn) {
195
703
  return Object.fromEntries(Object.entries(obj).filter(([key, value]) => fn(key, value)));
196
704
  }
705
+ /**
706
+ * 从对象中选取指定的属性
707
+ * @param obj - 输入对象
708
+ * @param keys - 要选取的键
709
+ * @returns 包含指定属性的新对象
710
+ * @example
711
+ * ```ts
712
+ * const obj = { a: 1, b: 2, c: 3, d: 4 }
713
+ * objectPick(obj, 'a', 'c') // { a: 1, c: 3 }
714
+ * objectPick(obj, 'a', 'x') // { a: 1 }
715
+ * objectPick(obj) // {}
716
+ * ```
717
+ */
197
718
  function objectPick(obj, ...keys) {
198
719
  return objectFilter(obj, (key) => keys.includes(key));
199
720
  }
721
+ /**
722
+ * 从对象中排除指定的属性
723
+ * @param obj - 输入对象
724
+ * @param keys - 要排除的键
725
+ * @returns 不包含指定属性的新对象
726
+ * @example
727
+ * ```ts
728
+ * const obj = { a: 1, b: 2, c: 3, d: 4 }
729
+ * objectOmit(obj, 'a', 'c') // { b: 2, d: 4 }
730
+ * objectOmit(obj, 'a', 'x') // { b: 2, c: 3, d: 4 }
731
+ * objectOmit(obj) // { a: 1, b: 2, c: 3, d: 4 }
732
+ * ```
733
+ */
200
734
  function objectOmit(obj, ...keys) {
201
735
  return objectFilter(obj, (key) => !keys.includes(key));
202
736
  }
737
+ /**
738
+ * 清除对象中值为 undefined 的属性
739
+ * @param obj - 输入对象
740
+ * @returns 清除 undefined 后的对象
741
+ * @example
742
+ * ```ts
743
+ * clearUndefined({ a: 1, b: undefined, c: 3 }) // { a: 1, c: 3 }
744
+ * clearUndefined({ a: undefined }) // {}
745
+ * clearUndefined({ a: null, b: undefined }) // { a: null } // null 不会被清除
746
+ * ```
747
+ */
203
748
  function clearUndefined(obj) {
204
749
  return objectFilter(obj, (_, value) => notUndefined(value));
205
750
  }
206
751
 
207
752
  //#endregion
208
753
  //#region src/base/regexp.ts
754
+ /**
755
+ * 判断值是否为正则表达式
756
+ * @param val - 要判断的值
757
+ * @returns 是否为正则表达式
758
+ * @example
759
+ * ```ts
760
+ * isRegExp(/test/) // true
761
+ * isRegExp(new RegExp('test')) // true
762
+ * isRegExp('test') // false
763
+ * isRegExp(null) // false
764
+ * ```
765
+ */
209
766
  const isRegExp = (val) => toString(val) === "[object RegExp]";
210
767
 
211
768
  //#endregion