-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathutils.js
314 lines (279 loc) · 8.48 KB
/
utils.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
/**
* 一些工具类函数
*/
//类型判断
const checkType = {
isNull: (val) => {
return Object.prototype.toString.call(val) === "[object Null]";
},
isUndefined: (val) => {
return Object.prototype.toString.call(val) === "[object Undefined]";
},
isArray: (val) => {
return Object.prototype.toString.call(val) === "[object Array]";
},
isObject: (val) => {
return Object.prototype.toString.call(val) === "[object Object]";
},
isNumber: (val) => {
return Object.prototype.toString.call(val) === "[object Number]";
},
isString: (val) => {
return Object.prototype.toString.call(val) === "[object String]";
},
isFunction: (val) => {
return Object.prototype.toString.call(val) === "[object Function]";
},
getType: (val) => {
let type = Object.prototype.toString.call(val);
const arr = type.match(/\[object\s([\s\S]*)\]/);
return arr[1];
}
}
//日期格式化
const formatDate = (date, fmt = "yyyy-MM-dd hh:mm:ss") => {
if (date) {
date = new Date(date);
let o = {
"M+": date.getMonth() + 1,
"d+": date.getDate().toString().length === 1 ? `0${date.getDate()}` : date.getDate(),
"h+": date.getHours(),
"m+": date.getMinutes(),
"s+": date.getSeconds()
};
if (/(y+)/.test(fmt)) {
fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "")).substr(4 - RegExp.$1.length);
}
for (let k in o) {
if (new RegExp("(" + k + ")").test(fmt)) {
fmt = fmt.replace(RegExp.$1, o[k].toString().length === 1 ? `0${o[k]}` : o[k]);
}
}
return fmt;
}
}
//判断两个对象相等
const isEqual = (a, b, aStack, bStack) =>{
// === 结果为 true 的区别出 +0 和 -0
if (a === b) return a !== 0 || 1 / a === 1 / b;
// typeof null 的结果为 object ,这里做判断,是为了让有 null 的情况尽早退出函数
if (a == null || b == null) return false;
// 判断 NaN
if (a !== a) return b !== b;
// 判断参数 a 类型,如果是基本类型,在这里可以直接返回 false
let type = typeof a;
if (type !== 'function' && type !== 'object' && typeof b != 'object') return false;
// 更复杂的对象使用 deepEq 函数进行深度比较
return deepEq(a, b, aStack, bStack);
};
function deepEq(a, b, aStack, bStack) {
// a 和 b 的内部属性 [[class]] 相同时 返回 true
let className = toString.call(a);
if (className !== toString.call(b)) return false;
switch (className) {
case '[object RegExp]':
case '[object String]':
return '' + a === '' + b;
case '[object Number]':
if (+a !== +a) return +b !== +b;
return +a === 0 ? 1 / +a === 1 / b : +a === +b;
case '[object Date]':
case '[object Boolean]':
return +a === +b;
}
let areArrays = className === '[object Array]';
// 不是数组
if (!areArrays) {
// 过滤掉两个函数的情况
if (typeof a != 'object' || typeof b != 'object') return false;
let aCtor = a.constructor, bCtor = b.constructor;
// aCtor 和 bCtor 必须都存在并且都不是 Object 构造函数的情况下,aCtor 不等于 bCtor, 那这两个对象就真的不相等啦
if (aCtor !== bCtor && !(checkType.isFunction(aCtor) && aCtor instanceof aCtor && checkType.isFunction(bCtor) && bCtor instanceof bCtor)
&& ('constructor' in a && 'constructor' in b)) {
return false;
}
}
// 数组判断
if (areArrays) {
let length = a.length;
if (length !== b.length) return false;
while (length--) {
if (!isEqual(a[length], b[length])) return false;
}
}else { //对象判断
let keys = Object.keys(a), key;
let length = keys.length;
if (Object.keys(b).length !== length) return false;
while (length--) {
key = keys[length];
if (!(b.hasOwnProperty(key) && isEqual(a[key], b[key]))) return false;
}
}
return true;
}
/**
* 组合函数
* @param {...any} args
* 函数作为参数且该函数的返回值作为另一个函数的参数
*/
const compose = (...args) => {
let start = args.length-1;
return function(){
let result = args[start].apply(this, arguments);
let i = start - 1;
while(i >= 0){
result = args[i].call(this, result);
i--;
}
return result
}
}
//深拷贝
const DeepClone = (source, hash=new WeakMap()) => {
if(source === null) return null;
//为了解决循环引用和相同引用的问题,存放已经递归到的目标对象
if(hash.get(source)) return hash.get(source);
//基本数据类型
if(source && (typeof source !== "object")) return source;
//其它类型:Map、Set、Date、正则
if(source && (typeof source === "object" || typeof source === "function")){
let result;
//Array类型
let target = Array.isArray(source) ? [] : {};
let type = Object.prototype.toString.call(source);
//引用类型的深拷贝函数
let clone = (keys) => {
keys.forEach(key => {
if(source[key] && (typeof source[key] === "object")){
target[key] = DeepClone(source[key]);
}else{
target[key] = source[key];
}
});
hash.set(source, target);
return target;
}
switch(type){
case "[object Object]":
return clone(Object.keys(source));
case "[object Map]":
result = new Map();
source.forEach((value, key) => {
result.set(key, DeepClone(value, hash))
})
return result;
case "[object Set]":
result = new Set();
source.forEach((key, value) => {
result.add(DeepClone(value, hash));
})
return result;
case "[object Symbol]":
//Symbol类型
let symKeys = Object.getOwnPropertySymbols(source);
if(symKeys.length){
return clone(symKeys);
}
break;
case "[object Date]":
result = new Date(source);
return result;
default:
result = source;
return result; //正则
}
}
}
/**
* blob格式下载或导出
*/
const downBlob = (blob, fileName) => {
const a = document.createElement("a");
document.body.appendChild(a);
if(fileName){
a.download = fileName;
}
a.href = URL.createObjectURL(blob);
a.click();
document.body.removeChild(a);
}
const checkFile = ({file, accepts=["txt","pdf","doc","jpg","png","xls","xlsx","ppt","pptx","docx"], size=1099511627776}) => {
return new Promise((resolve, reject) => {
if(!(file instanceof File)){
reject("请上传文件!");
return false;
}
//读取文件名和文件大小
const {name:fileName, size:fileSize} = file;
//读取文件后缀名
const fileExt = (str=>{
const arr = str.split(".");
if(!arr.length){
return "";
}else{
return arr[arr.length - 1]
}
})(fileName);
//判断文件格式
if((accepts instanceof Array) && !accepts.includes(fileExt.toLocaleLowerCase())){
reject(`请上传${accepts.join("、")}文件!`);
return false;
}
//判断文件大小
if(fileSize > size){
reject(`上传文件不应该超过${size/1024/1024}MB!`);
return false;
}
resolve(file);
})
}
/**
* try-catch封装
*/
function tryCatch(fn, ...args) {
try {
const result = fn.apply(null, args);
if (result.then) {
return new Promise(resolve => {
result
.then(v => resolve([undefined, v]))
.catch(e => resolve([e, undefined]))
});
}
return [undefined, result];
} catch (e) {
return [e, undefined];
}
}
function throws() {
throw new Error("It threw");
}
async function asyncSum(first, second) {
return first + second;
}
async function asyncThrows() {
throw new Error("It throws async");
}
// returns a sum
// prints [ undefined, 2 ]
console.log(tryCatch(Math.sqrt, 4));
// returns an error
// prints [ Error: 'It threw', undefined ]
console.log(tryCatch(throws));
// returns a promise resolving to value
// prints [ undefined, 3 ]
console.log(await tryCatch(asyncSum, 1, 2));
// returns a promise resolving to error
// prints [ Error: 'It throws async', undefined ]
console.log(await tryCatch(asyncThrows));
const utils = {
checkType,
formatDate,
isEqual,
compose,
DeepClone,
downBlob,
checkFile,
tryCatch
}
module.exports = utils;