@syzlm/function 1.0.0

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.
Files changed (90) hide show
  1. package/README.md +111 -0
  2. package/dist/arrays/arrayUtils.d.ts +20 -0
  3. package/dist/arrays/arrayUtils.d.ts.map +1 -0
  4. package/dist/arrays/index.d.ts +2 -0
  5. package/dist/arrays/index.d.ts.map +1 -0
  6. package/dist/index.cjs.js +2 -0
  7. package/dist/index.cjs.js.map +1 -0
  8. package/dist/index.d.ts +6 -0
  9. package/dist/index.d.ts.map +1 -0
  10. package/dist/index.js +2 -0
  11. package/dist/index.js.map +1 -0
  12. package/dist/numbers/index.d.ts +2 -0
  13. package/dist/numbers/index.d.ts.map +1 -0
  14. package/dist/numbers/numberUtils.d.ts +31 -0
  15. package/dist/numbers/numberUtils.d.ts.map +1 -0
  16. package/dist/objects/index.d.ts +2 -0
  17. package/dist/objects/index.d.ts.map +1 -0
  18. package/dist/objects/objectUtils.d.ts +36 -0
  19. package/dist/objects/objectUtils.d.ts.map +1 -0
  20. package/dist/storage.d.ts +13 -0
  21. package/dist/storage.d.ts.map +1 -0
  22. package/dist/strings/index.d.ts +2 -0
  23. package/dist/strings/index.d.ts.map +1 -0
  24. package/dist/strings/stringUtils.d.ts +51 -0
  25. package/dist/strings/stringUtils.d.ts.map +1 -0
  26. package/dist/utils/index.d.ts +2 -0
  27. package/dist/utils/index.d.ts.map +1 -0
  28. package/dist/utils/utilFunctions.d.ts +21 -0
  29. package/dist/utils/utilFunctions.d.ts.map +1 -0
  30. package/docs/.nojekyll +1 -0
  31. package/docs/assets/hierarchy.js +1 -0
  32. package/docs/assets/highlight.css +85 -0
  33. package/docs/assets/icons.js +18 -0
  34. package/docs/assets/icons.svg +1 -0
  35. package/docs/assets/main.js +60 -0
  36. package/docs/assets/navigation.js +1 -0
  37. package/docs/assets/search.js +1 -0
  38. package/docs/assets/style.css +1633 -0
  39. package/docs/functions/capitalize.html +4 -0
  40. package/docs/functions/chunk.html +5 -0
  41. package/docs/functions/clamp.html +6 -0
  42. package/docs/functions/debounce.html +5 -0
  43. package/docs/functions/deepClone.html +4 -0
  44. package/docs/functions/delay.html +4 -0
  45. package/docs/functions/get.html +6 -0
  46. package/docs/functions/getFontLength.html +4 -0
  47. package/docs/functions/getFontWidth.html +5 -0
  48. package/docs/functions/isPlainObject.html +4 -0
  49. package/docs/functions/merge.html +5 -0
  50. package/docs/functions/parseStrEmpty.html +4 -0
  51. package/docs/functions/randomString.html +4 -0
  52. package/docs/functions/range.html +6 -0
  53. package/docs/functions/round.html +5 -0
  54. package/docs/functions/set.html +6 -0
  55. package/docs/functions/shuffle.html +4 -0
  56. package/docs/functions/thousandSign.html +4 -0
  57. package/docs/functions/thousandSignZero.html +5 -0
  58. package/docs/functions/throttle.html +5 -0
  59. package/docs/functions/toCamelCase.html +4 -0
  60. package/docs/functions/toFixed.html +5 -0
  61. package/docs/functions/unique.html +4 -0
  62. package/docs/hierarchy.html +1 -0
  63. package/docs/index.html +53 -0
  64. package/docs/modules.html +1 -0
  65. package/jest.config.js +8 -0
  66. package/package.json +43 -0
  67. package/rollup.config.js +29 -0
  68. package/scripts/deploy-docs.sh +40 -0
  69. package/src/arrays/arrayUtils.ts +36 -0
  70. package/src/arrays/index.ts +2 -0
  71. package/src/index.ts +17 -0
  72. package/src/numbers/index.ts +2 -0
  73. package/src/numbers/numberUtils.ts +121 -0
  74. package/src/objects/index.ts +2 -0
  75. package/src/objects/objectUtils.ts +107 -0
  76. package/src/storage/index.ts +1 -0
  77. package/src/storage/storage.ts +83 -0
  78. package/src/strings/index.ts +2 -0
  79. package/src/strings/stringUtils.ts +120 -0
  80. package/src/utils/index.ts +2 -0
  81. package/src/utils/utilFunctions.ts +45 -0
  82. package/test-output.txt +23 -0
  83. package/test-tofixed.js +36 -0
  84. package/tests/arrays.test.ts +89 -0
  85. package/tests/numbers.test.ts +140 -0
  86. package/tests/objects.test.ts +189 -0
  87. package/tests/strings.test.ts +197 -0
  88. package/tests/utils.test.ts +121 -0
  89. package/tsconfig.json +21 -0
  90. package/typedoc.json +15 -0
@@ -0,0 +1,121 @@
1
+ /**
2
+ * 数字范围生成函数
3
+ * @param start 起始数字
4
+ * @param end 结束数字
5
+ * @param step 步长
6
+ * @returns 生成的数字数组
7
+ */
8
+ export function range(start: number, end: number, step: number = 1): number[] {
9
+ const result: number[] = [];
10
+ for (let i = start; i <= end; i += step) {
11
+ result.push(i);
12
+ }
13
+ return result;
14
+ }
15
+
16
+ /**
17
+ * 数字四舍五入函数
18
+ * @param num 需要四舍五入的数字
19
+ * @param decimals 保留小数位数
20
+ * @returns 四舍五入后的数字
21
+ */
22
+ export function round(num: number, decimals: number = 0): number {
23
+ const factor = Math.pow(10, decimals);
24
+ return Math.round(num * factor) / factor;
25
+ }
26
+
27
+ /**
28
+ * 数字在指定范围内的限制函数
29
+ * @param num 需要限制的数字
30
+ * @param min 最小值
31
+ * @param max 最大值
32
+ * @returns 限制后的数字
33
+ */
34
+ export function clamp(num: number, min: number, max: number): number {
35
+ return Math.min(Math.max(num, min), max);
36
+ }
37
+
38
+ /**
39
+ * 精确的数字toFixed函数
40
+ * @param num 需要处理的数字
41
+ * @param digits 保留小数位数
42
+ * @returns 格式化后的字符串
43
+ */
44
+ export function toFixed(num: number, digits: number = 0): string {
45
+ // 转换为字符串以避免浮点数精度问题
46
+ let numStr = String(num);
47
+ let isNegative = numStr.startsWith('-');
48
+ if (isNegative) {
49
+ numStr = numStr.slice(1);
50
+ }
51
+
52
+ // 处理科学计数法
53
+ if (numStr.includes('e') || numStr.includes('E')) {
54
+ const [base, exponent] = numStr.split(/[eE]/);
55
+ let exp = parseInt(exponent);
56
+ let [intPart, decPart] = base.split('.');
57
+ decPart = decPart || '';
58
+
59
+ if (exp >= 0) {
60
+ // 科学计数法表示的是整数
61
+ numStr = intPart + decPart.padEnd(exp, '0');
62
+ } else {
63
+ // 科学计数法表示的是小数
64
+ numStr = '0.' + '0'.repeat(-exp - 1) + intPart + decPart;
65
+ }
66
+ }
67
+
68
+ // 分割整数和小数部分
69
+ let [integerPart, decimalPart] = numStr.split('.');
70
+ decimalPart = decimalPart || '';
71
+
72
+ // 处理保留小数位数
73
+ if (digits < 0) {
74
+ digits = 0;
75
+ }
76
+
77
+ // 四舍五入处理
78
+ if (decimalPart.length > digits) {
79
+ // 需要四舍五入
80
+ let roundDigit = parseInt(decimalPart[digits]);
81
+ let newDecimalPart = decimalPart.slice(0, digits);
82
+
83
+ // 如果下一位大于等于5,则进位
84
+ if (roundDigit >= 5) {
85
+ // 将小数部分转换为数字加1
86
+ let carry = 1;
87
+ const newDecimalArray = newDecimalPart.split('');
88
+
89
+ // 从小数部分的最后一位开始处理进位
90
+ for (let i = newDecimalArray.length - 1; i >= 0 && carry > 0; i--) {
91
+ let digit = parseInt(newDecimalArray[i]) + carry;
92
+ if (digit === 10) {
93
+ newDecimalArray[i] = '0';
94
+ carry = 1;
95
+ } else {
96
+ newDecimalArray[i] = digit.toString();
97
+ carry = 0;
98
+ }
99
+ }
100
+
101
+ newDecimalPart = newDecimalArray.join('');
102
+
103
+ // 如果小数部分全部进位了,则整数部分加1
104
+ if (carry > 0) {
105
+ integerPart = (parseInt(integerPart) + 1).toString();
106
+ }
107
+ }
108
+
109
+ decimalPart = newDecimalPart;
110
+ } else {
111
+ // 不足位数补零
112
+ decimalPart = decimalPart.padEnd(digits, '0');
113
+ }
114
+
115
+ // 拼接结果
116
+ if (digits === 0) {
117
+ return (isNegative ? '-' : '') + integerPart;
118
+ } else {
119
+ return (isNegative ? '-' : '') + integerPart + '.' + decimalPart;
120
+ }
121
+ }
@@ -0,0 +1,2 @@
1
+ // 对象工具函数目录入口
2
+ export * from './objectUtils';
@@ -0,0 +1,107 @@
1
+ /**
2
+ * 对象深拷贝函数
3
+ * @param obj 需要深拷贝的对象
4
+ * @returns 深拷贝后的新对象
5
+ */
6
+ export function deepClone<T>(obj: T): T {
7
+ if (obj === null || typeof obj !== 'object') {
8
+ return obj;
9
+ }
10
+
11
+ if (obj instanceof Date) {
12
+ return new Date(obj.getTime()) as unknown as T;
13
+ }
14
+
15
+ if (obj instanceof Array) {
16
+ return obj.map(item => deepClone(item)) as unknown as T;
17
+ }
18
+
19
+ if (typeof obj === 'object') {
20
+ const clonedObj = {} as T;
21
+ for (const key in obj) {
22
+ if (obj.hasOwnProperty(key)) {
23
+ clonedObj[key as keyof T] = deepClone(obj[key as keyof T]);
24
+ }
25
+ }
26
+ return clonedObj;
27
+ }
28
+
29
+ return obj;
30
+ }
31
+
32
+ /**
33
+ * 对象合并函数
34
+ * @param target 目标对象
35
+ * @param sources 源对象列表
36
+ * @returns 合并后的对象
37
+ */
38
+ export function merge<T extends object>(target: T, ...sources: any[]): T {
39
+ return Object.assign({}, target, ...sources);
40
+ }
41
+
42
+ /**
43
+ * 获取对象属性值(支持路径访问)
44
+ * @param obj 目标对象
45
+ * @param path 属性路径,如 'a.b.c'
46
+ * @param defaultValue 默认值
47
+ * @returns 属性值或默认值
48
+ */
49
+ export function get(obj: any, path: string, defaultValue?: any): any {
50
+ const keys = path.split('.');
51
+ let result: any = obj;
52
+
53
+ for (const key of keys) {
54
+ if (result === null || result === undefined) {
55
+ return defaultValue;
56
+ }
57
+ result = result[key];
58
+ }
59
+
60
+ return result === undefined ? defaultValue : result;
61
+ }
62
+
63
+ /**
64
+ * 设置对象属性值(支持路径访问)
65
+ * @param obj 目标对象
66
+ * @param path 属性路径,如 'a.b.c'
67
+ * @param value 要设置的值
68
+ * @returns 设置后的对象
69
+ */
70
+ export function set<T extends Record<string, any>>(obj: T, path: string, value: any): T {
71
+ const keys = path.split('.');
72
+ let current: Record<string, any> = obj;
73
+
74
+ for (let i = 0; i < keys.length - 1; i++) {
75
+ const key = keys[i];
76
+ if (current[key] === null || current[key] === undefined) {
77
+ current[key] = {};
78
+ }
79
+ current = current[key];
80
+ }
81
+
82
+ current[keys[keys.length - 1]] = value;
83
+ return obj;
84
+ }
85
+
86
+ /**
87
+ * 检查一个值是否是普通对象
88
+ * @param value 要检查的值
89
+ * @returns 如果是普通对象返回true,否则返回false
90
+ */
91
+ export function isPlainObject(value: any): value is object {
92
+ if (value === null || typeof value !== 'object') {
93
+ return false;
94
+ }
95
+
96
+ const proto = Object.getPrototypeOf(value);
97
+
98
+ // 对象的原型应该是null或者Object.prototype
99
+ return proto === null || proto === Object.prototype;
100
+ }
101
+
102
+ /**
103
+ * @description 检测对象是否存在指定属性
104
+ * @param {object} obj 带检测对象
105
+ * @param {string} str 属性名称
106
+ */
107
+ export default (obj: object, str: string) => obj && Object.prototype.hasOwnProperty.call(obj, str);
@@ -0,0 +1 @@
1
+ export * from './storage';
@@ -0,0 +1,83 @@
1
+ /*
2
+ * @Description:
3
+ * @LastEditTime: 2025-10-11 15:51:11
4
+ * @FilePath: /admin/src/libs/storage.ts
5
+ */
6
+ import { isPlainObject } from '../objects';
7
+
8
+ // 重命名为与原代码一致的名称,保持兼容性
9
+ const isStrictObject = isPlainObject;
10
+
11
+ function getItem(storage: Storage, keys: string, needParse = true) {
12
+ const name = String(keys);
13
+ if (!name) {
14
+ if (process.env.NODE_ENV === 'development') {
15
+ console.error('请输入getItem方法的name');
16
+ }
17
+ return null;
18
+ }
19
+ try {
20
+ const result = storage.getItem(name) || '';
21
+ const reg = /^(\[|\{)[\s\S]*(\]|\})$/g;
22
+ if (needParse && reg.test(result as string)) {
23
+ return JSON.parse(result);
24
+ }
25
+ return result;
26
+ } catch (err) {
27
+ console.error('getItem:', err);
28
+ }
29
+ return null;
30
+ }
31
+ /**
32
+ * @func 本地存储存数据
33
+ * @return <Object, String>
34
+ * @param name <Object, String> 存储名称
35
+ * @param value <String> 存储值
36
+ */
37
+ function setItem(
38
+ storage: Storage,
39
+ keys: string,
40
+ value: string | object | object[] | string[] | number[],
41
+ ) {
42
+ const name = String(keys);
43
+ let storageValue = value;
44
+ if (!name) {
45
+ if (process.env.NODE_ENV === 'development') {
46
+ console.error('请输入setItem方法的key');
47
+ }
48
+ return;
49
+ }
50
+ if (Array.isArray(storageValue) || isStrictObject(storageValue)) {
51
+ storageValue = JSON.stringify(value);
52
+ } else {
53
+ storageValue = String(value || '');
54
+ }
55
+ storage.setItem(name, storageValue);
56
+ }
57
+ /**
58
+ * 清除本地缓存
59
+ */
60
+ function removeItem(storage: Storage, keys: string) {
61
+ const name = String(keys);
62
+ if (!name) return;
63
+ storage.removeItem(name);
64
+ }
65
+
66
+ function clear(storage: Storage) {
67
+ storage.clear();
68
+ }
69
+
70
+ export const sessionStorage = {
71
+ setItem: (k: string, a: any) => setItem(window.sessionStorage, k, a),
72
+ getItem: (k: string, needParse = true) => getItem(window.sessionStorage, k, needParse),
73
+ removeItem: (k: string) => removeItem(window.sessionStorage, k),
74
+ clear: () => clear(window.sessionStorage),
75
+
76
+ };
77
+
78
+ export const localStorage = {
79
+ setItem: (k: string, a: any) => setItem(window.localStorage, k, a),
80
+ getItem: (k: string, needParse = true) => getItem(window.localStorage, k, needParse),
81
+ removeItem: (k: string) => removeItem(window.localStorage, k),
82
+ clear: () => clear(window.localStorage),
83
+ };
@@ -0,0 +1,2 @@
1
+ // 字符串工具函数目录入口
2
+ export * from './stringUtils';
@@ -0,0 +1,120 @@
1
+
2
+
3
+ import { toFixed } from '../numbers/numberUtils';
4
+
5
+ /**
6
+ * 字符串驼峰命名转换函数
7
+ * @param str 需要转换的字符串
8
+ * @returns 驼峰命名的字符串
9
+ */
10
+ export function toCamelCase(str: string): string {
11
+ return str.replace(/[-_\s]+(.)?/g, (_, c) => c ? c.toUpperCase() : '');
12
+ }
13
+
14
+ /**
15
+ * 字符串首字母大写函数
16
+ * @param str 需要转换的字符串
17
+ * @returns 首字母大写的字符串
18
+ */
19
+ export function capitalize(str: string): string {
20
+ if (!str) return str;
21
+ return str.charAt(0).toUpperCase() + str.slice(1);
22
+ }
23
+
24
+ /**
25
+ * 生成随机字符串函数
26
+ * @param length 字符串长度
27
+ * @returns 随机字符串
28
+ */
29
+ export function randomString(length: number): string {
30
+ const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
31
+ let result = '';
32
+ for (let i = 0; i < length; i++) {
33
+ result += chars.charAt(Math.floor(Math.random() * chars.length));
34
+ }
35
+ return result;
36
+ }
37
+
38
+
39
+ /**
40
+ * 转换字符串,undefined,null等转化为""
41
+ * @param str 需要转换的字符串
42
+ * @returns 转换后的字符串
43
+ */
44
+ export function parseStrEmpty(str: string): string {
45
+ if (!str || str === 'undefined' || str === 'null') {
46
+ return '';
47
+ }
48
+ return str;
49
+ }
50
+
51
+ /**
52
+ * 获取字符串的字体长度
53
+ * @param str 需要计算长度的字符串
54
+ * @returns 字符串的字体长度(中文字符算2个长度,英文字符算1个长度)
55
+ */
56
+ export function getFontLength(str: string): number {
57
+ let len = 0;
58
+ for (let i = 0; i < str.length; i++) {
59
+ if (str.charCodeAt(i) > 127 || str.charCodeAt(i) === 94) {
60
+ len += 2;
61
+ } else {
62
+ len += 1;
63
+ }
64
+ }
65
+ return len;
66
+ }
67
+
68
+ /**
69
+ * 获取文字宽度
70
+ * @param str 需要计算宽度的字符串
71
+ * @param fontStyle 字体样式,可选,默认使用系统默认字体
72
+ * @returns 文字宽度(像素)
73
+ */
74
+ export function getFontWidth(str: string, fontStyle?: string): number {
75
+ let canvas: any | null = typeof document !== 'undefined' ? document.createElement('canvas') : null;
76
+ const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
77
+ ctx.font =
78
+ fontStyle ||
79
+ '600 14px / 22px -apple-system, "system-ui", "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"';
80
+ const width = ctx.measureText(str).width;
81
+
82
+ canvas = null;
83
+ return width;
84
+ }
85
+
86
+ /**
87
+ * 千分位格式化
88
+ * @param num 需要格式化的数字或字符串
89
+ * @returns 千分位格式化后的字符串
90
+ */
91
+ export function thousandSign(num: number | string): string {
92
+ if (num) {
93
+ const [integer, decimal] = String(num).split('.');
94
+ let ret = integer.replace(/\d(?=(\d{3})+$)/g, '$&,');
95
+ if (decimal) {
96
+ ret += Number(decimal) > 0 ? `${parseFloat(`0.${decimal}`)}`.replace(/0\./, '.') : '';
97
+ }
98
+ return ret;
99
+ }
100
+ return String(num || '0').replace(/\d(?=(\d{3})+$)/g, '$&,');
101
+ }
102
+ /**
103
+ * 千分位格式化 自动补零
104
+ * @param num 需要格式化的数字或字符串
105
+ * @param fixed 保留的小数位数,默认2位
106
+ * @returns 千分位格式化后的字符串
107
+ */
108
+ export function thousandSignZero(num: number | string, fixed?: number): string {
109
+ if (num) {
110
+ // 使用精确的toFixed函数
111
+ const numStr = toFixed(Number(num), fixed || 2);
112
+ const [integer, decimal] = numStr.split('.');
113
+ let ret = integer.replace(/\d(?=(\d{3})+$)/g, '$&,');
114
+ if (decimal) {
115
+ ret += `.${decimal}`;
116
+ }
117
+ return ret;
118
+ }
119
+ return String(num || '0.00').replace(/\d(?=(\d{3})+$)/g, '$&,');
120
+ }
@@ -0,0 +1,2 @@
1
+ // 通用工具函数目录入口
2
+ export * from './utilFunctions';
@@ -0,0 +1,45 @@
1
+ /**
2
+ * 防抖函数
3
+ * @param func 需要防抖的函数
4
+ * @param wait 等待时间(毫秒)
5
+ * @returns 防抖后的函数
6
+ */
7
+ export function debounce<T extends (...args: any[]) => any>(
8
+ func: T,
9
+ wait: number
10
+ ): (...args: Parameters<T>) => void {
11
+ let timeoutId: NodeJS.Timeout;
12
+ return (...args: Parameters<T>) => {
13
+ clearTimeout(timeoutId);
14
+ timeoutId = setTimeout(() => func(...args), wait);
15
+ };
16
+ }
17
+
18
+ /**
19
+ * 节流函数
20
+ * @param func 需要节流的函数
21
+ * @param limit 限制时间(毫秒)
22
+ * @returns 节流后的函数
23
+ */
24
+ export function throttle<T extends (...args: any[]) => any>(
25
+ func: T,
26
+ limit: number
27
+ ): (...args: Parameters<T>) => void {
28
+ let inThrottle: boolean;
29
+ return (...args: Parameters<T>) => {
30
+ if (!inThrottle) {
31
+ func(...args);
32
+ inThrottle = true;
33
+ setTimeout(() => inThrottle = false, limit);
34
+ }
35
+ };
36
+ }
37
+
38
+ /**
39
+ * 延迟函数
40
+ * @param ms 延迟时间(毫秒)
41
+ * @returns Promise对象
42
+ */
43
+ export function delay(ms: number): Promise<void> {
44
+ return new Promise(resolve => setTimeout(resolve, ms));
45
+ }
@@ -0,0 +1,23 @@
1
+ -------------------|---------|----------|---------|---------|-------------------
2
+ File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
3
+ -------------------|---------|----------|---------|---------|-------------------
4
+ All files | 22.07 | 25.61 | 9.52 | 22.59 |
5
+ src | 0 | 0 | 0 | 0 |
6
+ index.ts | 0 | 100 | 100 | 0 | 5-17
7
+ storage.ts | 0 | 0 | 0 | 0 | 6-82
8
+ src/arrays | 0 | 100 | 0 | 0 |
9
+ arrayUtils.ts | 0 | 100 | 0 | 0 | 6-35
10
+ index.ts | 0 | 100 | 100 | 0 | 2
11
+ src/numbers | 96.07 | 93.93 | 100 | 95.91 |
12
+ index.ts | 0 | 100 | 100 | 0 | 2
13
+ numberUtils.ts | 98 | 93.93 | 100 | 97.91 | 61
14
+ src/objects | 0 | 0 | 0 | 0 |
15
+ index.ts | 0 | 100 | 100 | 0 | 2
16
+ objectUtils.ts | 0 | 0 | 0 | 0 | 6-99
17
+ src/strings | 0 | 0 | 0 | 0 |
18
+ index.ts | 0 | 100 | 100 | 0 | 2
19
+ stringUtils.ts | 0 | 0 | 0 | 0 | 3-115
20
+ src/utils | 0 | 0 | 0 | 0 |
21
+ index.ts | 0 | 100 | 100 | 0 | 2
22
+ utilFunctions.ts | 0 | 0 | 0 | 0 | 7-44
23
+ -------------------|---------|----------|---------|---------|-------------------
@@ -0,0 +1,36 @@
1
+ // 测试精确的toFixed函数
2
+ const { toFixed } = require('./dist/index.js');
3
+
4
+ // 测试用例:原生toFixed有问题的小数
5
+ const testCases = [
6
+ 0.1,
7
+ 0.2,
8
+ 0.1 + 0.2,
9
+ 1.005,
10
+ 2.56789,
11
+ -0.1,
12
+ -1.005,
13
+ 1234.56789
14
+ ];
15
+
16
+ console.log('测试精确的toFixed函数:');
17
+ console.log('====================================');
18
+ console.log('数字 | 原生toFixed(2) | 精确toFixed(2)');
19
+ console.log('====================================');
20
+
21
+ testCases.forEach(num => {
22
+ const nativeResult = num.toFixed(2);
23
+ const preciseResult = toFixed(num, 2);
24
+ console.log(`${num} | ${nativeResult} | ${preciseResult}`);
25
+ });
26
+
27
+ console.log('====================================');
28
+ console.log('\n测试不同小数位数:');
29
+ console.log('====================================');
30
+
31
+ const num = 1.005;
32
+ for (let i = 1; i <= 5; i++) {
33
+ const nativeResult = num.toFixed(i);
34
+ const preciseResult = toFixed(num, i);
35
+ console.log(`toFixed(${i}) | 原生: ${nativeResult} | 精确: ${preciseResult}`);
36
+ }
@@ -0,0 +1,89 @@
1
+ import { unique, shuffle, chunk } from '../src/arrays/arrayUtils';
2
+
3
+ describe('数组工具函数测试', () => {
4
+ describe('unique 函数', () => {
5
+ it('应该正确去重基本类型数组', () => {
6
+ expect(unique([1, 2, 2, 3, 4, 4, 5])).toEqual([1, 2, 3, 4, 5]);
7
+ expect(unique(['a', 'b', 'b', 'c'])).toEqual(['a', 'b', 'c']);
8
+ expect(unique([true, false, true])).toEqual([true, false]);
9
+ });
10
+
11
+ it('应该正确处理空数组', () => {
12
+ expect(unique([])).toEqual([]);
13
+ });
14
+
15
+ it('应该正确处理没有重复元素的数组', () => {
16
+ expect(unique([1, 2, 3, 4, 5])).toEqual([1, 2, 3, 4, 5]);
17
+ });
18
+
19
+ it('应该正确处理包含多种类型元素的数组', () => {
20
+ const arr = [1, '1', 2, '2', true, false, true];
21
+ const result = unique(arr);
22
+ expect(result.length).toBe(6);
23
+ expect(result).toContain(1);
24
+ expect(result).toContain('1');
25
+ expect(result).toContain(2);
26
+ expect(result).toContain('2');
27
+ expect(result).toContain(true);
28
+ expect(result).toContain(false);
29
+ });
30
+ });
31
+
32
+ describe('shuffle 函数', () => {
33
+ it('应该随机打乱数组元素', () => {
34
+ const arr = [1, 2, 3, 4, 5];
35
+ const shuffled = shuffle(arr);
36
+
37
+ // 检查数组长度是否相同
38
+ expect(shuffled.length).toBe(arr.length);
39
+
40
+ // 检查所有元素是否都在
41
+ expect(shuffled).toEqual(expect.arrayContaining(arr));
42
+
43
+ // 检查顺序是否被打乱(虽然有极小概率顺序不变,但多次测试应该会通过)
44
+ const results = new Set();
45
+ for (let i = 0; i < 10; i++) {
46
+ results.add(JSON.stringify(shuffle(arr)));
47
+ }
48
+ expect(results.size).toBeGreaterThan(1);
49
+ });
50
+
51
+ it('应该不修改原始数组', () => {
52
+ const arr = [1, 2, 3, 4, 5];
53
+ const original = [...arr];
54
+ shuffle(arr);
55
+ expect(arr).toEqual(original);
56
+ });
57
+
58
+ it('应该正确处理空数组', () => {
59
+ expect(shuffle([])).toEqual([]);
60
+ });
61
+
62
+ it('应该正确处理单元素数组', () => {
63
+ expect(shuffle([42])).toEqual([42]);
64
+ });
65
+ });
66
+
67
+ describe('chunk 函数', () => {
68
+ it('应该正确将数组分块', () => {
69
+ expect(chunk([1, 2, 3, 4, 5, 6], 2)).toEqual([[1, 2], [3, 4], [5, 6]]);
70
+ expect(chunk([1, 2, 3, 4, 5], 2)).toEqual([[1, 2], [3, 4], [5]]);
71
+ });
72
+
73
+ it('应该正确处理空数组', () => {
74
+ expect(chunk([], 2)).toEqual([]);
75
+ });
76
+
77
+ it('应该正确处理数组长度正好是块大小的倍数', () => {
78
+ expect(chunk([1, 2, 3, 4, 5, 6], 3)).toEqual([[1, 2, 3], [4, 5, 6]]);
79
+ });
80
+
81
+ it('应该正确处理块大小大于数组长度的情况', () => {
82
+ expect(chunk([1, 2, 3], 5)).toEqual([[1, 2, 3]]);
83
+ });
84
+
85
+ it('应该正确处理块大小为1的情况', () => {
86
+ expect(chunk([1, 2, 3, 4, 5], 1)).toEqual([[1], [2], [3], [4], [5]]);
87
+ });
88
+ });
89
+ });