@polyv/utils 1.5.1 → 2.0.0-beta.1
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/README.md +33 -18
- package/dist/cjs/boolean.d.ts +45 -0
- package/dist/cjs/boolean.js +1 -0
- package/dist/cjs/countdown.d.ts +97 -0
- package/dist/cjs/countdown.js +1 -0
- package/dist/cjs/date.d.ts +44 -0
- package/dist/cjs/date.js +1 -0
- package/dist/cjs/json.d.ts +43 -0
- package/dist/cjs/json.js +1 -0
- package/dist/cjs/net.d.ts +32 -0
- package/dist/cjs/net.js +1 -0
- package/dist/cjs/string.d.ts +94 -0
- package/dist/cjs/string.js +1 -0
- package/dist/cjs/validate.d.ts +26 -0
- package/dist/cjs/validate.js +1 -0
- package/dist/es/boolean.d.ts +45 -0
- package/dist/es/boolean.js +1 -0
- package/dist/es/countdown.d.ts +97 -0
- package/dist/es/countdown.js +1 -0
- package/dist/es/date.d.ts +44 -0
- package/dist/es/date.js +1 -0
- package/dist/es/json.d.ts +43 -0
- package/dist/es/json.js +1 -0
- package/dist/es/net.d.ts +32 -0
- package/dist/es/net.js +1 -0
- package/dist/es/string.d.ts +94 -0
- package/dist/es/string.js +1 -0
- package/dist/es/validate.d.ts +26 -0
- package/dist/es/validate.js +1 -0
- package/package.json +31 -26
- package/dist/boolean.js +0 -1
- package/dist/browser.js +0 -1
- package/dist/cookie.js +0 -1
- package/dist/countdown.js +0 -1
- package/dist/date.js +0 -1
- package/dist/lang.js +0 -1
- package/dist/net.js +0 -1
- package/dist/polling.js +0 -1
- package/dist/querystring.js +0 -1
- package/dist/storage.js +0 -1
- package/dist/string.js +0 -1
- package/dist/validate.js +0 -1
- package/src/boolean.js +0 -67
- package/src/browser.js +0 -81
- package/src/cookie.js +0 -115
- package/src/countdown.js +0 -91
- package/src/date.js +0 -92
- package/src/internal/core.js +0 -59
- package/src/internal/timeunit.js +0 -63
- package/src/lang.js +0 -120
- package/src/net.js +0 -54
- package/src/polling.js +0 -142
- package/src/querystring.js +0 -121
- package/src/storage.js +0 -106
- package/src/string.js +0 -105
- package/src/validate.js +0 -42
package/src/cookie.js
DELETED
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 本模块提供 cookie 读写方法。
|
|
3
|
-
* @module cookie
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { isDate } from './internal/core';
|
|
7
|
-
import { addToDate } from './internal/timeunit';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* 写入 cookie。
|
|
11
|
-
* @author luoliquan
|
|
12
|
-
* @param {string} key cookie 键。
|
|
13
|
-
* @param {string} value cookie 值。
|
|
14
|
-
* @param {Object} [options] 参数。
|
|
15
|
-
* @param {string} [options.domain] 所在域。
|
|
16
|
-
* @param {string} [options.path] 所在路径。
|
|
17
|
-
* @param {(Date|number|string)} [options.expires] 过期时间。
|
|
18
|
-
* 为日期类型时表示绝对时间;
|
|
19
|
-
* 为数字(单位毫秒)时表示相对时间(当前时间+相对值);
|
|
20
|
-
* 为字符串时表示相对时间(当前时间+相对值),支持格式包括(%表示数字):
|
|
21
|
-
* %secs,
|
|
22
|
-
* %mins,
|
|
23
|
-
* %hours,
|
|
24
|
-
* %days,
|
|
25
|
-
* %months,
|
|
26
|
-
* %years。
|
|
27
|
-
* @param {boolean} [options.secure] 是否只在 https 连接中有效。
|
|
28
|
-
* @param {string} [options.sameSite] 访问限制:Lax、Strict 或 None。
|
|
29
|
-
* @example
|
|
30
|
-
* cookie.set('a', '1')
|
|
31
|
-
* cookie.set('b', '2', {
|
|
32
|
-
* expires: '6months', // 180 天
|
|
33
|
-
* domain: '.polyv.net',
|
|
34
|
-
* path: '/'
|
|
35
|
-
* });
|
|
36
|
-
*/
|
|
37
|
-
export function set(key, value, options) {
|
|
38
|
-
options = options || {};
|
|
39
|
-
|
|
40
|
-
let content = encodeURIComponent(key) + '=' + encodeURIComponent(value);
|
|
41
|
-
if (options.expires != null) {
|
|
42
|
-
content += '; expires=' + (
|
|
43
|
-
isDate(options.expires) ?
|
|
44
|
-
options.expires :
|
|
45
|
-
addToDate(new Date(), options.expires)
|
|
46
|
-
).toUTCString();
|
|
47
|
-
}
|
|
48
|
-
if (options.path) { content += '; path=' + options.path; }
|
|
49
|
-
if (options.domain) { content += '; domain=' + options.domain; }
|
|
50
|
-
if (options.secure === true) { content += '; secure'; }
|
|
51
|
-
if (options.sameSite) {
|
|
52
|
-
const sameSite = String(options.sameSite).toLowerCase();
|
|
53
|
-
if (['lax', 'strict', 'none'].indexOf(sameSite) !== -1) {
|
|
54
|
-
content += '; samesite=' + sameSite;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
document.cookie = content;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* 读取 cookie。
|
|
63
|
-
* @author luoliquan
|
|
64
|
-
* @param {string} name cookie 名。
|
|
65
|
-
* @return {string} cookie 值。
|
|
66
|
-
* @example
|
|
67
|
-
* cookie.get('a');
|
|
68
|
-
*/
|
|
69
|
-
export function get(key) {
|
|
70
|
-
key = '; ' + encodeURIComponent(key) + '=';
|
|
71
|
-
const cookie = '; ' + document.cookie;
|
|
72
|
-
|
|
73
|
-
let beginPos = cookie.indexOf(key);
|
|
74
|
-
if (beginPos === -1) { return null; }
|
|
75
|
-
beginPos += key.length;
|
|
76
|
-
|
|
77
|
-
let endPos = cookie.indexOf(';', beginPos);
|
|
78
|
-
if (endPos === -1) { endPos = cookie.length; }
|
|
79
|
-
|
|
80
|
-
return decodeURIComponent(cookie.substring(beginPos, endPos));
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// iOS 9 下设置过期不会马上生效,先设为空
|
|
84
|
-
const shouldSetEmptyBeforeRemove = (function() {
|
|
85
|
-
// 兼容 Node 端(主要针对同构应用)引入
|
|
86
|
-
if (typeof document === 'undefined') { return false; }
|
|
87
|
-
|
|
88
|
-
const TEST_KEY = '__jraiser__test__cookie__';
|
|
89
|
-
document.cookie = TEST_KEY + '=1';
|
|
90
|
-
document.cookie = TEST_KEY + '=;expires=Thu, 01 Jan 1970 00:00:00 GMT';
|
|
91
|
-
return !!get(TEST_KEY);
|
|
92
|
-
})();
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* 移除 cookie。
|
|
96
|
-
* @author luoliquan
|
|
97
|
-
* @param {string} name cookie 名。
|
|
98
|
-
* @param {Object} [options] 参数。
|
|
99
|
-
* @param {string} [options.domain] 所在域。
|
|
100
|
-
* @param {string} [options.path] 所在路径。
|
|
101
|
-
* @example
|
|
102
|
-
* remove('a');
|
|
103
|
-
* remove('b' {
|
|
104
|
-
* domain: '.polyv.net',
|
|
105
|
-
* path: '/abc'
|
|
106
|
-
* })
|
|
107
|
-
*/
|
|
108
|
-
export function remove(name, options) {
|
|
109
|
-
if (shouldSetEmptyBeforeRemove) { set(name, '', options); }
|
|
110
|
-
|
|
111
|
-
options = options || {};
|
|
112
|
-
// 让其过期即为删除
|
|
113
|
-
options.expires = new Date(0);
|
|
114
|
-
set(name, '', options);
|
|
115
|
-
}
|
package/src/countdown.js
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 本模块提供倒数功能。
|
|
3
|
-
* @module countdown
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const computes = [
|
|
7
|
-
{ divisor: 24 * 60 * 60 * 1000, unit: 'days' },
|
|
8
|
-
{ divisor: 60 * 60 * 1000, unit: 'hours' },
|
|
9
|
-
{ divisor: 60 * 1000, unit: 'minutes' },
|
|
10
|
-
{ divisor: 1000, unit: 'seconds' }
|
|
11
|
-
];
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* 倒计时回调函数。
|
|
15
|
-
* @callback countdownCallback
|
|
16
|
-
* @memberof module:countdown.Countdown
|
|
17
|
-
* @param {Object} rest 剩余的时间。
|
|
18
|
-
* @param {number} rest.days 剩余天数。
|
|
19
|
-
* @param {number} rest.hours 剩余小时数。
|
|
20
|
-
* @param {number} rest.minutes 剩余分钟数。
|
|
21
|
-
* @param {number} rest.seconds 剩余秒数。
|
|
22
|
-
* @param {boolean} rest.totalMsecs 剩余的总毫秒数。
|
|
23
|
-
*/
|
|
24
|
-
/**
|
|
25
|
-
* 倒计时类。
|
|
26
|
-
* @memberof module:countdown
|
|
27
|
-
* @class
|
|
28
|
-
* @name Countdown
|
|
29
|
-
* @author luoliquan
|
|
30
|
-
* @param {number} secs 总秒数。
|
|
31
|
-
* @param {countdownCallback} [cb] 回调函数。
|
|
32
|
-
* @example
|
|
33
|
-
* const countdown = new Countdown(60, (rest) => {
|
|
34
|
-
* console.dir(rest);
|
|
35
|
-
* });
|
|
36
|
-
* countdown.start();
|
|
37
|
-
*/
|
|
38
|
-
export default class Countdown {
|
|
39
|
-
constructor(secs, cb) {
|
|
40
|
-
secs = parseInt(secs);
|
|
41
|
-
if (isNaN(secs)) { throw new Error('Total seconds must be a number'); }
|
|
42
|
-
this._secs = secs * 1000; // 倒计时毫秒数
|
|
43
|
-
this._cb = typeof cb === 'function' ? cb : function() {}; // 倒计时回调函数
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
_exec() {
|
|
47
|
-
if (!this._startTime) { return; }
|
|
48
|
-
|
|
49
|
-
let value = Math.max(0, this._secs - (Date.now() - this._startTime));
|
|
50
|
-
if (value > 0 && !this._stopped) {
|
|
51
|
-
setTimeout(() => { this._exec(); }, 1000);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (value >= 0) {
|
|
55
|
-
const rest = {
|
|
56
|
-
totalMsecs: value
|
|
57
|
-
};
|
|
58
|
-
computes.forEach((item, i) => {
|
|
59
|
-
rest[item.unit] = value / item.divisor;
|
|
60
|
-
if (i === computes.length - 1) {
|
|
61
|
-
rest[item.unit] = Math.round(rest[item.unit]);
|
|
62
|
-
} else {
|
|
63
|
-
rest[item.unit] = Math.floor(rest[item.unit]);
|
|
64
|
-
value = value % item.divisor;
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
this._cb(rest);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* 开始倒计时。
|
|
73
|
-
* @method
|
|
74
|
-
* @memberof module:countdown.Countdown.prototype
|
|
75
|
-
*/
|
|
76
|
-
start() {
|
|
77
|
-
if (this.secs <= 0) { return; }
|
|
78
|
-
this._startTime = Date.now();
|
|
79
|
-
this._exec();
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* 停止倒计时。
|
|
84
|
-
* @method
|
|
85
|
-
* @memberof module:countdown.Countdown.prototype
|
|
86
|
-
*/
|
|
87
|
-
stop() {
|
|
88
|
-
if (this._timerId) { clearTimeout(this._timerId); }
|
|
89
|
-
this._stopped = true;
|
|
90
|
-
}
|
|
91
|
-
}
|
package/src/date.js
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 本模块提供日期处理相关方法。
|
|
3
|
-
* @module date
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { extend } from './lang';
|
|
7
|
-
|
|
8
|
-
// 保证日期相关函数的操作对象为日期类型
|
|
9
|
-
export function ensureDate(date) {
|
|
10
|
-
if (typeof date !== 'object') { date = new Date(date); }
|
|
11
|
-
return date;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* 格式化日期。
|
|
16
|
-
* @author luoliquan
|
|
17
|
-
* @param {(Date|number)} date 日期对象或时间戳(毫秒)。
|
|
18
|
-
* @param {string} formation 格式。
|
|
19
|
-
* @return {string} 格式化结果。
|
|
20
|
-
* @example
|
|
21
|
-
* formatDate(new Date(2018, 9, 8, 8, 50, 56), 'YYYY-MM-DD hh:mm:ss'); // '2018-10-08 08:50:56'
|
|
22
|
-
*/
|
|
23
|
-
export function formatDate(date, formation) {
|
|
24
|
-
date = ensureDate(date);
|
|
25
|
-
|
|
26
|
-
const values = {
|
|
27
|
-
Y: date.getFullYear(),
|
|
28
|
-
M: date.getMonth() + 1,
|
|
29
|
-
D: date.getDate(),
|
|
30
|
-
h: date.getHours(),
|
|
31
|
-
m: date.getMinutes(),
|
|
32
|
-
s: date.getSeconds()
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
return formation.replace(/([YMDhms])\1*/g, (match) => {
|
|
36
|
-
let result = values[match[0]];
|
|
37
|
-
if (match.length > 1 && result.toString().length !== match.length) {
|
|
38
|
-
result = ((new Array(match.length)).join('0') + result).slice(-match.length);
|
|
39
|
-
}
|
|
40
|
-
return result;
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* 把秒数格式化成「时:分:秒」格式。
|
|
46
|
-
* @author luoliquan
|
|
47
|
-
* @param {number} secs 秒数。
|
|
48
|
-
* @param {Object} [options] 格式化配置。
|
|
49
|
-
* @param {number} [options.segments=2] 段数,2 或者 3。
|
|
50
|
-
* 为 2 时,如果小时为 0,则格式化样式为「分:秒」。
|
|
51
|
-
* @param {number} [options.digits=2] 每一段数字的最小位数,不足位数时补 0。
|
|
52
|
-
* @return {string} 格式化结果。
|
|
53
|
-
* @example
|
|
54
|
-
* formatSeconds(3682); // '01:01:22'
|
|
55
|
-
* formatSeconds(82); // '01:22'
|
|
56
|
-
* formatSeconds(82, { segments: 3 }); // '00:01:22'
|
|
57
|
-
* formatSeconds(3682, { digits: 1 }); // '1:1:22'
|
|
58
|
-
*/
|
|
59
|
-
export function formatSeconds(secs, options) {
|
|
60
|
-
secs = Number(secs);
|
|
61
|
-
if (isNaN(secs) || secs < 0) {
|
|
62
|
-
throw new Error('"secs" must be a positive integer');
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// 参数合法性校验
|
|
66
|
-
options = extend({}, options);
|
|
67
|
-
options.segments = parseInt(options.segments);
|
|
68
|
-
// 位数最小为 1
|
|
69
|
-
options.digits = Math.max(1, parseInt(options.digits) || 2);
|
|
70
|
-
// 段数只能为 2 或者 3
|
|
71
|
-
if ([2, 3].indexOf(options.segments) === -1) {
|
|
72
|
-
options.segments = 2;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// 需要补多少个 0
|
|
76
|
-
const zeros = (new Array(options.digits + 1).join('0'));
|
|
77
|
-
|
|
78
|
-
const result = [
|
|
79
|
-
60 * 60,
|
|
80
|
-
60,
|
|
81
|
-
1
|
|
82
|
-
].map((num) => {
|
|
83
|
-
const subResult = Math.floor(secs / num);
|
|
84
|
-
const len = subResult.toString().length;
|
|
85
|
-
secs = secs % num;
|
|
86
|
-
return (zeros + subResult).slice(-Math.max(len, options.digits));
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
if (options.segments < 3 && !Number(result[0])) { result.shift(); }
|
|
90
|
-
|
|
91
|
-
return result.join(':');
|
|
92
|
-
}
|
package/src/internal/core.js
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module internal-core
|
|
3
|
-
* @ignore
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// ESLint 不推荐直接使用 obj.hasOwnProperty
|
|
7
|
-
const hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
8
|
-
/**
|
|
9
|
-
* 检查指定对象是否具有某个 own property。
|
|
10
|
-
* @function
|
|
11
|
-
* @name hasOwnProp
|
|
12
|
-
* @author luoliquan
|
|
13
|
-
* @param {Any} obj 指定对象。
|
|
14
|
-
* @param {string} prop 属性名。
|
|
15
|
-
* @return {boolean} 指定对象是否具有某个 own property。
|
|
16
|
-
*/
|
|
17
|
-
export function hasOwnProp(obj, prop) {
|
|
18
|
-
return hasOwnProperty.call(obj, prop);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// 单个源扩展
|
|
22
|
-
export function extendSingle(target, src) {
|
|
23
|
-
if (src != null) {
|
|
24
|
-
let key, value;
|
|
25
|
-
for (key in src) {
|
|
26
|
-
value = src[key];
|
|
27
|
-
if (key === '__proto__' || target === value) { continue; }
|
|
28
|
-
if (hasOwnProp(src, key)) { target[key] = value; }
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const toString = Object.prototype.toString;
|
|
35
|
-
|
|
36
|
-
// 是否 Object 类型
|
|
37
|
-
export function isObject(value) {
|
|
38
|
-
return toString.call(value) === '[object Object]';
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// 是否 Date 类型
|
|
42
|
-
export function isDate(value) {
|
|
43
|
-
return toString.call(value) === '[object Date]';
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* 全局对象,浏览器环境下为 window,Node 环境下为 global。
|
|
49
|
-
* @type {Object}
|
|
50
|
-
*/
|
|
51
|
-
let theGlobal;
|
|
52
|
-
if (typeof window !== 'undefined') {
|
|
53
|
-
theGlobal = window;
|
|
54
|
-
} else if (typeof global !== 'undefined') {
|
|
55
|
-
theGlobal = global;
|
|
56
|
-
} else {
|
|
57
|
-
theGlobal = null;
|
|
58
|
-
}
|
|
59
|
-
export { theGlobal };
|
package/src/internal/timeunit.js
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module
|
|
3
|
-
* @ignore
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { hasOwnProp } from './core';
|
|
7
|
-
|
|
8
|
-
// 时间单位
|
|
9
|
-
const timeUnits = {
|
|
10
|
-
SEC: 1000,
|
|
11
|
-
MIN: 60 * 1000,
|
|
12
|
-
HOUR: 60 * 60 * 1000,
|
|
13
|
-
DAY: 24 * 60 * 60 * 1000,
|
|
14
|
-
MONTH: 30 * 24 * 60 * 60 * 1000,
|
|
15
|
-
YEAR: 365 * 24 * 60 * 60 * 1000
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* 把带单位的时间跨度转换为毫秒表示。
|
|
20
|
-
* @author luoliquan
|
|
21
|
-
* @param {(number|string)} timespan 时间跨度。为数字时表示毫秒,为字符串时支持以下格式(%表示数字):
|
|
22
|
-
* %secs;
|
|
23
|
-
* %mins;
|
|
24
|
-
* %hours;
|
|
25
|
-
* %days;
|
|
26
|
-
* %months;
|
|
27
|
-
* %years。
|
|
28
|
-
* @return {number} 时间跨度的毫秒表示。
|
|
29
|
-
*/
|
|
30
|
-
export function parse(timespan) {
|
|
31
|
-
// str为数字,直接返回
|
|
32
|
-
if (typeof timespan === 'number') { return timespan; }
|
|
33
|
-
if (!isNaN(timespan)) { return Number(timespan); }
|
|
34
|
-
|
|
35
|
-
const num = parseFloat(timespan);
|
|
36
|
-
if (isNaN(num)) {
|
|
37
|
-
throw new Error('Invalid timespan string');
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const unit = timespan.split(num)[1]
|
|
41
|
-
.trim()
|
|
42
|
-
.toUpperCase()
|
|
43
|
-
.replace(/S$/, ''); // 移除复数时的s
|
|
44
|
-
|
|
45
|
-
if (hasOwnProp(timeUnits, unit)) {
|
|
46
|
-
return num * timeUnits[unit];
|
|
47
|
-
} else {
|
|
48
|
-
throw new Error('Invalid time unit "' + unit + '"');
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* 以指定日期对象的毫秒表示加上指定时间跨度的毫秒表示,生成新的日期对象。
|
|
54
|
-
* @author luoliquan
|
|
55
|
-
* @param {(Date|number)} date 指定日期对象或日期的毫秒表示。
|
|
56
|
-
* @param {(number|string)} timespan 时间跨度,为数字时表示毫秒,为字符串时支持的格式同 parse。
|
|
57
|
-
* @return {Date} 表示相加结果的日期对象。
|
|
58
|
-
*/
|
|
59
|
-
export function addToDate(date, timespan) {
|
|
60
|
-
return new Date(
|
|
61
|
-
(typeof date === 'number' ? date : date.getTime()) + parse(timespan)
|
|
62
|
-
);
|
|
63
|
-
}
|
package/src/lang.js
DELETED
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 本模块提供基础方法。
|
|
3
|
-
* @module lang
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { extendSingle, hasOwnProp, isObject } from './internal/core';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* 检查指定对象是否具有某个 own property(ESLint 不推荐直接使用 obj.hasOwnProperty)。
|
|
10
|
-
* @author luoliquan
|
|
11
|
-
* @name hasOwnProp
|
|
12
|
-
* @function
|
|
13
|
-
* @static
|
|
14
|
-
* @param {Any} obj 指定对象。
|
|
15
|
-
* @param {string} prop 属性名。
|
|
16
|
-
* @return {boolean} 指定对象是否具有某个 own property。
|
|
17
|
-
*/
|
|
18
|
-
export { hasOwnProp };
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* 检查指定对象是否为类数组结构。
|
|
22
|
-
* @author luoliquan
|
|
23
|
-
* @param {Any} obj 指定对象。
|
|
24
|
-
* @return {boolean} 检查指定对象是否为类数组结构。
|
|
25
|
-
* @example
|
|
26
|
-
* isArrayLike([]); // true
|
|
27
|
-
* isArrayLike(document.getElementsByTagName('body')); // true
|
|
28
|
-
* isArrayLike({}); // false
|
|
29
|
-
*/
|
|
30
|
-
export function isArrayLike(obj) {
|
|
31
|
-
return obj != null &&
|
|
32
|
-
typeof obj !== 'function' &&
|
|
33
|
-
typeof obj.length === 'number' &&
|
|
34
|
-
obj.length >= 0 &&
|
|
35
|
-
obj.length % 1 === 0; // 不是小数
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* 检查指定值是否为空数据。以下情况会判断为空数据:
|
|
40
|
-
* null 或者 undefined;
|
|
41
|
-
* 数组结构,但长度为 0;
|
|
42
|
-
* 空字符串或仅包含空白字符的字符串;
|
|
43
|
-
* 没有 own property 的纯对象。
|
|
44
|
-
* @author luoliquan
|
|
45
|
-
* @param {Any} value 指定值。
|
|
46
|
-
* @return {boolean} 指定值是否为空数据。
|
|
47
|
-
* @example
|
|
48
|
-
* isEmptyData(null); // true
|
|
49
|
-
* isEmptyData([]); // true
|
|
50
|
-
* isEmptyData(''); // true
|
|
51
|
-
* isEmptyData({}); // true
|
|
52
|
-
* isEmptyData({ a: 1 }); // false
|
|
53
|
-
* isEmptyData([1]); // false
|
|
54
|
-
*/
|
|
55
|
-
export function isEmptyData(value) {
|
|
56
|
-
if (value == null) { return true; }
|
|
57
|
-
if (typeof value === 'string') {
|
|
58
|
-
return value.trim() === '';
|
|
59
|
-
} else if (Array.isArray(value)) {
|
|
60
|
-
return !value.length;
|
|
61
|
-
} else if (isObject(value)) {
|
|
62
|
-
for (const key in value) {
|
|
63
|
-
if (hasOwnProp(value, key)) { return false; }
|
|
64
|
-
}
|
|
65
|
-
return true;
|
|
66
|
-
}
|
|
67
|
-
return false;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* 把源对象的属性(own property)扩展到目标对象(同 Object.assign)。
|
|
72
|
-
* @author luoliquan
|
|
73
|
-
* @param {Any} target 目标对象。
|
|
74
|
-
* @param {...Any} [source] 源对象。若有同名属性,则后者覆盖前者。
|
|
75
|
-
* @return {Any} 目标对象。
|
|
76
|
-
*/
|
|
77
|
-
export function extend(target) {
|
|
78
|
-
if (target == null) {
|
|
79
|
-
throw new Error('The target argument cannot be null or undefined');
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const len = arguments.length;
|
|
83
|
-
let i = 0;
|
|
84
|
-
while (++i < len) {
|
|
85
|
-
extendSingle(target, arguments[i]);
|
|
86
|
-
}
|
|
87
|
-
return target;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* 深度克隆指定对象(仅限 JSON 支持的数据类型)。
|
|
92
|
-
* @author liumin
|
|
93
|
-
* @param {Any} obj 指定对象。
|
|
94
|
-
* @return {Any} 克隆结果。
|
|
95
|
-
* @example
|
|
96
|
-
* cloneJSON({ a: 1, b: 2 }); // { a: 1, b: 2 }
|
|
97
|
-
*/
|
|
98
|
-
export function cloneJSON(obj) {
|
|
99
|
-
if (obj == null) { return obj; }
|
|
100
|
-
return JSON.parse(JSON.stringify(obj));
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* 尝试把指定字符串解析为 JSON 对象。
|
|
105
|
-
* @author luoliquan
|
|
106
|
-
* @param {string} str 指定字符串。
|
|
107
|
-
* @return {Any} 解析结果,解析失败时返回 undefined。
|
|
108
|
-
* @example
|
|
109
|
-
* tryParseJSON('ss&&**'); // undefined
|
|
110
|
-
* tryParseJSON('{"a": 1}'); // { a: 1 }
|
|
111
|
-
*/
|
|
112
|
-
export function tryParseJSON(str) {
|
|
113
|
-
let result;
|
|
114
|
-
try {
|
|
115
|
-
result = JSON.parse(str);
|
|
116
|
-
} catch (e) {
|
|
117
|
-
|
|
118
|
-
}
|
|
119
|
-
return result;
|
|
120
|
-
}
|
package/src/net.js
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 本模块提供网络协议相关方法。
|
|
3
|
-
* @module net
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// 匹配协议
|
|
7
|
-
const reProtocol = /^(?:([a-z]+):)?\/{2,3}/i;
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* 检查目标字符串是否以特定 URL 协议开头。
|
|
11
|
-
* @author luoliquan
|
|
12
|
-
* @param {string} str 目标字符串。
|
|
13
|
-
* @param {Array} [protocols] 特定协议(不含冒号和斜杠),不指定时表示允许任何协议。
|
|
14
|
-
* @return {boolean} 目标字符串是否以特定 URL 协议开头。
|
|
15
|
-
* @example
|
|
16
|
-
* startsWithProtocol('//abc.com'); // true
|
|
17
|
-
* startsWithProtocol('https://abc.com'); // true
|
|
18
|
-
* startsWithProtocol('file:///Users/'); // true
|
|
19
|
-
* startsWithProtocol('abc.com'); // false
|
|
20
|
-
* startsWithProtocol('http://abc.com', ['http', 'https']); // true
|
|
21
|
-
* startsWithProtocol('ftp://abc.com', ['http', 'https']); // false
|
|
22
|
-
*/
|
|
23
|
-
export function startsWithProtocol(str, protocols) {
|
|
24
|
-
const result = reProtocol.test(str);
|
|
25
|
-
if (result && protocols) {
|
|
26
|
-
const protocol = (RegExp.$1 || '').toLowerCase();
|
|
27
|
-
for (let i = protocols.length - 1; i >= 0; i--) {
|
|
28
|
-
if (protocol === protocols[i].toLowerCase()) {
|
|
29
|
-
return true;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
return false;
|
|
33
|
-
}
|
|
34
|
-
return result;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* 替换目标字符串中的 URL 协议。如果字符串中不包含协议,则加上协议。
|
|
39
|
-
* @author luoliquan
|
|
40
|
-
* @param {string} url 目标字符串。
|
|
41
|
-
* @param {string} protocol 协议。
|
|
42
|
-
* @return {string} 替换结果。
|
|
43
|
-
* @example
|
|
44
|
-
* changeProtocol('abc.com', 'https'); // 'https://abc.com'
|
|
45
|
-
* changeProtocol('http://abc.com', 'https'); // 'https://abc.com'
|
|
46
|
-
*/
|
|
47
|
-
export function changeProtocol(url, protocol) {
|
|
48
|
-
if (!reProtocol.test(protocol)) {
|
|
49
|
-
protocol += '://';
|
|
50
|
-
}
|
|
51
|
-
return startsWithProtocol(url) ?
|
|
52
|
-
url.replace(reProtocol, protocol) :
|
|
53
|
-
protocol + url;
|
|
54
|
-
}
|