cody-utils 1.0.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/.history/package_20200212101131.json +19 -0
- package/.history/package_20250527165758.json +19 -0
- package/.history/package_20250527165800.json +19 -0
- package/.history/package_20250527165806.json +19 -0
- package/.history/package_20250527165810.json +19 -0
- package/.history/package_20250527165815.json +19 -0
- package/.history/package_20250527165817.json +19 -0
- package/.history/package_20250527165826.json +19 -0
- package/.history/package_20250527165829.json +19 -0
- package/.history/package_20250527165835.json +19 -0
- package/.history/package_20250527170050.json +19 -0
- package/.history/package_20250527170051.json +19 -0
- package/.history/webpack.config_20200212101131.js +23 -0
- package/.history/webpack.config_20250527165622.js +23 -0
- package/.history/webpack.config_20250527165631.js +23 -0
- package/.history/webpack.config_20250527165643.js +23 -0
- package/.history/webpack.config_20250527165647.js +23 -0
- package/README.md +124 -0
- package/dist/cody-utils.min.js +435 -0
- package/package.json +19 -0
- package/src/array/chunk.js +30 -0
- package/src/array/compact.js +6 -0
- package/src/array/concat.js +16 -0
- package/src/array/declares.js +92 -0
- package/src/array/difference.js +12 -0
- package/src/array/drop.js +28 -0
- package/src/array/flatten.js +28 -0
- package/src/array/merge.js +18 -0
- package/src/array/pull.js +33 -0
- package/src/array/slice.js +33 -0
- package/src/array/unique.js +40 -0
- package/src/axios/index.js +97 -0
- package/src/event-bus/index.js +46 -0
- package/src/function/apply.js +17 -0
- package/src/function/bind.js +18 -0
- package/src/function/call.js +17 -0
- package/src/function/debounce.js +22 -0
- package/src/function/throttle.js +15 -0
- package/src/index.js +30 -0
- package/src/object/clone.js +34 -0
- package/src/object/deepClone.js +105 -0
- package/src/object/merge.js +14 -0
- package/src/object/myInstanceOf.js +22 -0
- package/src/object/newInstance.js +20 -0
- package/src/promise/index.js +226 -0
- package/src/pub-sub/index.js +95 -0
- package/src/string/index.js +28 -0
- package/test/01_call_apply_bind.html +47 -0
- package/test/02_throttle_debounce.html +54 -0
- package/test/02_/345/207/275/346/225/260/351/230/262/346/212/226/344/270/216/350/212/202/346/265/201.jpg +0 -0
- package/test/03_array_declare.html +51 -0
- package/test/04_array_unique.html +32 -0
- package/test/05_array_concat_slice.html +28 -0
- package/test/06_array_flatten.html +23 -0
- package/test/07_array_compact_chunk.html +25 -0
- package/test/08_array_difference_merge.html +22 -0
- package/test/09_array_pull_pullAll.html +27 -0
- package/test/10_array_drop_dropRight.html +32 -0
- package/test/11_new_instanceof.html +47 -0
- package/test/12_object_merge.html +34 -0
- package/test/13_deepClone.html +42 -0
- package/test/13_shallowClone.html +27 -0
- package/test/13_/346/265/213/350/257/225/351/201/215/345/216/206/345/257/271/350/261/241/346/225/210/347/216/207.html +38 -0
- package/test/13_/346/265/213/350/257/225/351/201/215/345/216/206/346/225/260/347/273/204/346/225/210/347/216/207.html +60 -0
- package/test/14_string.html +21 -0
- package/test/15_/346/211/213/345/206/231/347/273/247/346/211/277.html +53 -0
- package/test/16_/346/211/213/345/206/231/344/272/213/344/273/266/346/200/273/347/272/277.html +32 -0
- package/test/17_/346/211/213/345/206/231/346/266/210/346/201/257/350/256/242/351/230/205/344/270/216/345/217/221/345/270/203.html +48 -0
- package/test/18_/346/211/213/345/206/231Promise.html +49 -0
- package/test/19_/346/211/213/345/206/231ajax/350/257/267/346/261/202/345/207/275/346/225/260.html +102 -0
- package/test/20_/346/225/260/346/215/256/347/273/223/346/236/204/344/270/216/347/256/227/346/263/225/01_/345/237/272/346/234/254/346/225/260/346/215/256/347/273/223/346/236/204_/346/225/260/347/273/204//346/225/260/347/273/204/345/270/270/350/247/201/346/223/215/344/275/2341.html +48 -0
- package/test/20_/346/225/260/346/215/256/347/273/223/346/236/204/344/270/216/347/256/227/346/263/225/01_/345/237/272/346/234/254/346/225/260/346/215/256/347/273/223/346/236/204_/346/225/260/347/273/204//346/225/260/347/273/204/345/270/270/350/247/201/346/223/215/344/275/2342.html +74 -0
- package/test/20_/346/225/260/346/215/256/347/273/223/346/236/204/344/270/216/347/256/227/346/263/225/01_/345/237/272/346/234/254/346/225/260/346/215/256/347/273/223/346/236/204_/346/225/260/347/273/204//346/225/260/347/273/204/345/270/270/350/247/201/346/223/215/344/275/2343.html +53 -0
- package/test/20_/346/225/260/346/215/256/347/273/223/346/236/204/344/270/216/347/256/227/346/263/225/01_/345/237/272/346/234/254/346/225/260/346/215/256/347/273/223/346/236/204_/346/225/260/347/273/204//346/225/260/347/273/204/345/270/270/350/247/201/346/223/215/344/275/2344.html +54 -0
- package/test/20_/346/225/260/346/215/256/347/273/223/346/236/204/344/270/216/347/256/227/346/263/225/02_/345/237/272/346/234/254/346/225/260/346/215/256/347/273/223/346/236/204_/346/240/210//346/240/210_/345/272/224/347/224/250_/345/215/201/350/277/233/345/210/266/350/275/254/344/272/214/350/277/233/345/210/266.html +41 -0
- package/test/20_/346/225/260/346/215/256/347/273/223/346/236/204/344/270/216/347/256/227/346/263/225/02_/345/237/272/346/234/254/346/225/260/346/215/256/347/273/223/346/236/204_/346/240/210//346/240/210_/346/265/213/350/257/225.html +29 -0
- package/test/20_/346/225/260/346/215/256/347/273/223/346/236/204/344/270/216/347/256/227/346/263/225/03_/345/237/272/346/234/254/346/225/260/346/215/256/347/273/223/346/236/204_/351/230/237/345/210/227//344/274/230/345/205/210/347/272/247/351/230/237/345/210/227_/346/265/213/350/257/225.html +29 -0
- package/test/20_/346/225/260/346/215/256/347/273/223/346/236/204/344/270/216/347/256/227/346/263/225/03_/345/237/272/346/234/254/346/225/260/346/215/256/347/273/223/346/236/204_/351/230/237/345/210/227//351/230/237/345/210/227_/345/272/224/347/224/250_/345/207/273/351/274/223/344/274/240/350/212/261.html +38 -0
- package/test/20_/346/225/260/346/215/256/347/273/223/346/236/204/344/270/216/347/256/227/346/263/225/03_/345/237/272/346/234/254/346/225/260/346/215/256/347/273/223/346/236/204_/351/230/237/345/210/227//351/230/237/345/210/227_/346/265/213/350/257/225.html +33 -0
- package/test/20_/346/225/260/346/215/256/347/273/223/346/236/204/344/270/216/347/256/227/346/263/225/04_/346/225/260/346/215/256/347/273/223/346/236/204_/351/223/276/350/241/250//345/217/214/345/220/221/351/223/276/350/241/250_/346/265/213/350/257/225.html +55 -0
- package/test/20_/346/225/260/346/215/256/347/273/223/346/236/204/344/270/216/347/256/227/346/263/225/04_/346/225/260/346/215/256/347/273/223/346/236/204_/351/223/276/350/241/250//351/223/276/350/241/250_/346/265/213/350/257/225.html +52 -0
- package/test/20_/346/225/260/346/215/256/347/273/223/346/236/204/344/270/216/347/256/227/346/263/225/05_/346/225/260/346/215/256/347/273/223/346/236/204_/346/240/221//344/272/214/345/217/211/346/220/234/347/264/242/346/240/221_/346/265/213/350/257/225.html +48 -0
- package/test/20_/346/225/260/346/215/256/347/273/223/346/236/204/344/270/216/347/256/227/346/263/225/06_/346/225/260/346/215/256/347/273/223/346/236/204_/351/233/206/345/220/210//351/233/206/345/220/210_/346/265/213/350/257/225.html +50 -0
- package/test/20_/346/225/260/346/215/256/347/273/223/346/236/204/344/270/216/347/256/227/346/263/225/07_/346/216/222/345/272/217/347/256/227/346/263/225/3/347/247/215/345/237/272/346/234/254/346/216/222/345/272/217_/346/265/213/350/257/225.html +19 -0
- package/test/20_/346/225/260/346/215/256/347/273/223/346/236/204/344/270/216/347/256/227/346/263/225/07_/346/216/222/345/272/217/347/256/227/346/263/225//351/253/230/347/272/247/346/216/222/345/272/217_/346/265/213/350/257/225.html +19 -0
- package/test/README.md +207 -0
- package/test/db.json +54 -0
- package/webpack.config.js +23 -0
- package//350/207/252/345/256/232/344/271/211npm/345/267/245/345/205/267/345/272/223.md +91 -0
@@ -0,0 +1,105 @@
|
|
1
|
+
/*
|
2
|
+
深度克隆
|
3
|
+
1). 大众乞丐版
|
4
|
+
问题1: 函数属性会丢失
|
5
|
+
问题2: 循环引用会出错
|
6
|
+
2). 面试基础版本
|
7
|
+
解决问题1: 函数属性还没丢失
|
8
|
+
3). 面试加强版本
|
9
|
+
解决问题2: 循环引用正常
|
10
|
+
4). 面试加强版本2(优化遍历性能)
|
11
|
+
数组: while | for | forEach() 优于 for-in | keys()&forEach()
|
12
|
+
对象: for-in 与 keys()&forEach() 差不多
|
13
|
+
*/
|
14
|
+
/*
|
15
|
+
1). 大众乞丐版
|
16
|
+
问题1: 函数属性会丢失
|
17
|
+
问题2: 循环引用会出错
|
18
|
+
*/
|
19
|
+
export function deepClone1(target) {
|
20
|
+
return JSON.parse(JSON.stringify(target))
|
21
|
+
}
|
22
|
+
|
23
|
+
/*
|
24
|
+
获取数据的类型字符串名
|
25
|
+
*/
|
26
|
+
function getType(data) {
|
27
|
+
return Object.prototype.toString.call(data).slice(8, -1)
|
28
|
+
}
|
29
|
+
|
30
|
+
/*
|
31
|
+
2). 面试基础版本
|
32
|
+
解决问题1: 函数属性还没丢失
|
33
|
+
*/
|
34
|
+
export function deepClone2(target) {
|
35
|
+
const type = getType(target)
|
36
|
+
|
37
|
+
if (type==='Object' || type==='Array') {
|
38
|
+
const cloneTarget = type === 'Array' ? [] : {}
|
39
|
+
for (const key in target) {
|
40
|
+
if (target.hasOwnProperty(key)) {
|
41
|
+
cloneTarget[key] = deepClone2(target[key])
|
42
|
+
}
|
43
|
+
}
|
44
|
+
return cloneTarget
|
45
|
+
} else {
|
46
|
+
return target
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
/*
|
51
|
+
3). 面试加强版本
|
52
|
+
解决问题2: 循环引用正常
|
53
|
+
*/
|
54
|
+
export function deepClone3(target, map = new Map()) {
|
55
|
+
const type = getType(target)
|
56
|
+
if (type==='Object' || type==='Array') {
|
57
|
+
let cloneTarget = map.get(target)
|
58
|
+
if (cloneTarget) {
|
59
|
+
return cloneTarget
|
60
|
+
}
|
61
|
+
cloneTarget = type==='Array' ? [] : {}
|
62
|
+
map.set(target, cloneTarget)
|
63
|
+
for (const key in target) {
|
64
|
+
if (target.hasOwnProperty(key)) {
|
65
|
+
cloneTarget[key] = deepClone3(target[key], map)
|
66
|
+
}
|
67
|
+
}
|
68
|
+
return cloneTarget
|
69
|
+
} else {
|
70
|
+
return target
|
71
|
+
}
|
72
|
+
}
|
73
|
+
|
74
|
+
/*
|
75
|
+
4). 面试加强版本2(优化遍历性能)
|
76
|
+
数组: while | for | forEach() 优于 for-in | keys()&forEach()
|
77
|
+
对象: for-in 与 keys()&forEach() 差不多
|
78
|
+
*/
|
79
|
+
export function deepClone4(target, map = new Map()) {
|
80
|
+
const type = getType(target)
|
81
|
+
if (type==='Object' || type==='Array') {
|
82
|
+
let cloneTarget = map.get(target)
|
83
|
+
if (cloneTarget) {
|
84
|
+
return cloneTarget
|
85
|
+
}
|
86
|
+
|
87
|
+
if (type==='Array') {
|
88
|
+
cloneTarget = []
|
89
|
+
map.set(target, cloneTarget)
|
90
|
+
target.forEach((item, index) => {
|
91
|
+
cloneTarget[index] = deepClone4(item, map)
|
92
|
+
})
|
93
|
+
} else {
|
94
|
+
cloneTarget = {}
|
95
|
+
map.set(target, cloneTarget)
|
96
|
+
Object.keys(target).forEach(key => {
|
97
|
+
cloneTarget[key] = deepClone4(target[key], map)
|
98
|
+
})
|
99
|
+
}
|
100
|
+
|
101
|
+
return cloneTarget
|
102
|
+
} else {
|
103
|
+
return target
|
104
|
+
}
|
105
|
+
}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
/*
|
2
|
+
merge(...objs): 合并多个对象, 返回一个合并后对象(不改变原对象)
|
3
|
+
{ a: [{ x: 2 }, { y: 4 }], b: 1}
|
4
|
+
{ a: { z: 3}, b: [2, 3], c: 'foo'}
|
5
|
+
合并后: { a: [ { x: 2 }, { y: 4 }, { z: 3 } ], b: [ 1, 2, 3 ], c: 'foo' }
|
6
|
+
*/
|
7
|
+
export function mergeObject(...objs) {
|
8
|
+
return objs.reduce((pre, obj) => {
|
9
|
+
return Object.keys(obj).reduce((p, key) => {
|
10
|
+
p[key] = !p.hasOwnProperty(key) ? obj[key] : [].concat(p[key], obj[key])
|
11
|
+
return p
|
12
|
+
}, pre)
|
13
|
+
}, {})
|
14
|
+
}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
/*
|
2
|
+
自定义instanceof工具函数:
|
3
|
+
语法: myInstanceOf(obj, Type)
|
4
|
+
功能: 判断obj是否是Type类型的实例
|
5
|
+
实现: Type的原型对象是否是obj的原型链上的某个对象, 如果是返回true, 否则返回false
|
6
|
+
*/
|
7
|
+
export function myInstanceOf(obj, Type) {
|
8
|
+
// 得到原型对象
|
9
|
+
let protoObj = obj.__proto__
|
10
|
+
|
11
|
+
// 只要原型对象存在
|
12
|
+
while(protoObj) {
|
13
|
+
// 如果原型对象是Type的原型对象, 返回true
|
14
|
+
if (protoObj === Type.prototype) {
|
15
|
+
return true
|
16
|
+
}
|
17
|
+
// 指定原型对象的原型对象
|
18
|
+
protoObj = protoObj.__proto__
|
19
|
+
}
|
20
|
+
|
21
|
+
return false
|
22
|
+
}
|
@@ -0,0 +1,20 @@
|
|
1
|
+
/*
|
2
|
+
自定义new工具函数
|
3
|
+
语法: newInstance(Fn, ...args)
|
4
|
+
功能: 创建Fn构造函数的实例对象
|
5
|
+
实现: 创建空对象obj, 调用Fn指定this为obj, 返回obj
|
6
|
+
*/
|
7
|
+
export function newInstance(Fn, ...args) {
|
8
|
+
// 创建一个新的对象
|
9
|
+
const obj = {}
|
10
|
+
// 执行构造函数
|
11
|
+
const result = Fn.apply(obj, args) // 相当于: obj.Fn()
|
12
|
+
// 如果构造函数执行的结果是对象, 返回这个对象
|
13
|
+
if (result instanceof Object) {
|
14
|
+
return result
|
15
|
+
}
|
16
|
+
// 如果不是, 返回新创建的对象
|
17
|
+
obj.__proto__.constructor = Fn // 让原型对象的构造器属性指向Fn
|
18
|
+
|
19
|
+
return obj
|
20
|
+
}
|
@@ -0,0 +1,226 @@
|
|
1
|
+
const PENDING = 'pending' // 初始未确定的状态
|
2
|
+
const RESOLVED = 'resolved' // 成功的状态
|
3
|
+
const REJECTED = 'rejected' // 失败的状态
|
4
|
+
|
5
|
+
/*
|
6
|
+
Promise构造函数
|
7
|
+
*/
|
8
|
+
function Promise(excutor) {
|
9
|
+
|
10
|
+
const self = this // Promise的实例对象
|
11
|
+
self.status = PENDING // 状态属性, 初始值为pending, 代表初始未确定的状态
|
12
|
+
self.data = undefined // 用来存储结果数据的属性, 初始值为undefined
|
13
|
+
self.callbacks = [] // {onResolved(){}, onRejected(){}}
|
14
|
+
|
15
|
+
/*
|
16
|
+
将promise的状态改为成功, 指定成功的value
|
17
|
+
*/
|
18
|
+
function resolve(value) {
|
19
|
+
// 如果当前不是pending, 直接结束
|
20
|
+
if (self.status !== PENDING) return
|
21
|
+
|
22
|
+
self.status = RESOLVED // 将状态改为成功
|
23
|
+
self.data = value // 保存成功的value
|
24
|
+
|
25
|
+
// 异步调用所有缓存的待执行成功的回调函数
|
26
|
+
if (self.callbacks.length > 0) {
|
27
|
+
// 启动一个延迟时间为0的定时器, 在定时器的回调中执行所有成功的回调
|
28
|
+
setTimeout(() => {
|
29
|
+
self.callbacks.forEach(cbsObj => {
|
30
|
+
cbsObj.onResolved(value)
|
31
|
+
})
|
32
|
+
})
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
36
|
+
/*
|
37
|
+
将promise的状态改为失败, 指定失败的reason
|
38
|
+
*/
|
39
|
+
function reject(reason) {
|
40
|
+
// 如果当前不是pending, 直接结束
|
41
|
+
if (self.status !== PENDING) return
|
42
|
+
|
43
|
+
self.status = REJECTED // 将状态改为失败
|
44
|
+
self.data = reason // 保存reason数据
|
45
|
+
|
46
|
+
// 异步调用所有缓存的待执行失败的回调函数
|
47
|
+
if (self.callbacks.length > 0) {
|
48
|
+
// 启动一个延迟时间为0的定时器, 在定时器的回调中执行所有失败的回调
|
49
|
+
setTimeout(() => {
|
50
|
+
self.callbacks.forEach(cbsObj => {
|
51
|
+
cbsObj.onRejected(reason)
|
52
|
+
})
|
53
|
+
})
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
// 调用excutor来启动异步任务
|
58
|
+
try {
|
59
|
+
excutor(resolve, reject)
|
60
|
+
} catch (error) { // 执行器执行出错, 当前promise变为失败
|
61
|
+
console.log('-----')
|
62
|
+
reject(error)
|
63
|
+
}
|
64
|
+
|
65
|
+
}
|
66
|
+
|
67
|
+
/*
|
68
|
+
用来指定成功/失败回调函数的方法
|
69
|
+
1). 如果当前promise是resolved, 异步执行成功的回调函数onResolved
|
70
|
+
2). 如果当前promise是rejected, 异步执行成功的回调函数onRejected
|
71
|
+
3). 如果当前promise是pending, 保存回调函数
|
72
|
+
返回一个新的promise对象
|
73
|
+
它的结果状态由onResolved或者onRejected执行的结果决定
|
74
|
+
2.1). 抛出error ==> 变为rejected, 结果值为error
|
75
|
+
2.2). 返回值不是promise ==> 变为resolved, 结果值为返回值
|
76
|
+
2.3). 返回值是promise ===> 由这个promise的决定新的promise的结果(成功/失败)
|
77
|
+
*/
|
78
|
+
Promise.prototype.then = function (onResolved, onRejected) {
|
79
|
+
const self = this
|
80
|
+
|
81
|
+
onResolved = typeof onResolved === 'function' ? onResolved : value => value // 将value向下传递
|
82
|
+
onRejected = typeof onRejected === 'function' ? onRejected : reason => {
|
83
|
+
throw reason
|
84
|
+
} // 将reason向下传递
|
85
|
+
|
86
|
+
return new Promise((resolve, reject) => { // 什么时候改变它的状态
|
87
|
+
|
88
|
+
/*
|
89
|
+
1. 调用指定的回调函数
|
90
|
+
2. 根据回调执行结果来更新返回promise的状态
|
91
|
+
*/
|
92
|
+
function handle(callback) {
|
93
|
+
try {
|
94
|
+
const result = callback(self.data)
|
95
|
+
if (!(result instanceof Promise)) { // 2.2). 返回值不是promise ==> 变为resolved, 结果值为返回值
|
96
|
+
resolve(result)
|
97
|
+
} else { // 2.3). 返回值是promise ===> 由这个promise的决定新的promise的结果(成功/失败)
|
98
|
+
result.then(
|
99
|
+
value => resolve(value),
|
100
|
+
reason => reject(reason)
|
101
|
+
)
|
102
|
+
// result.then(resolve, reject)
|
103
|
+
}
|
104
|
+
} catch (error) { // 2.1). 抛出error ==> 变为rejected, 结果值为error
|
105
|
+
reject(error)
|
106
|
+
}
|
107
|
+
}
|
108
|
+
|
109
|
+
if (self.status === RESOLVED) {
|
110
|
+
setTimeout(() => {
|
111
|
+
handle(onResolved)
|
112
|
+
})
|
113
|
+
} else if (self.status === REJECTED) {
|
114
|
+
setTimeout(() => {
|
115
|
+
handle(onRejected)
|
116
|
+
})
|
117
|
+
} else { // PENDING
|
118
|
+
self.callbacks.push({
|
119
|
+
onResolved(value) {
|
120
|
+
handle(onResolved)
|
121
|
+
},
|
122
|
+
onRejected(reason) {
|
123
|
+
handle(onRejected)
|
124
|
+
}
|
125
|
+
})
|
126
|
+
}
|
127
|
+
})
|
128
|
+
}
|
129
|
+
|
130
|
+
/*
|
131
|
+
用来指定失败回调函数的方法
|
132
|
+
catch是then的语法糖
|
133
|
+
*/
|
134
|
+
Promise.prototype.catch = function (onRejected) {
|
135
|
+
return this.then(undefined, onRejected)
|
136
|
+
}
|
137
|
+
|
138
|
+
/*
|
139
|
+
用来返回一个指定vlaue的成功的promise
|
140
|
+
value可能是一个一般的值, 也可能是promise对象
|
141
|
+
*/
|
142
|
+
Promise.resolve = function (value) {
|
143
|
+
return new Promise((resolve, reject) => {
|
144
|
+
// 如果value是一个promise, 最终返回的promise的结果由value决定
|
145
|
+
if (value instanceof Promise) {
|
146
|
+
value.then(resolve, reject)
|
147
|
+
} else { // value不是promise, 返回的是成功的promise, 成功的值就是value
|
148
|
+
resolve(value)
|
149
|
+
}
|
150
|
+
})
|
151
|
+
}
|
152
|
+
|
153
|
+
/*
|
154
|
+
用来返回一个指定reason的失败的promise
|
155
|
+
*/
|
156
|
+
Promise.reject = function (reason) {
|
157
|
+
return new Promise((resolve, reject) => {
|
158
|
+
reject(reason)
|
159
|
+
})
|
160
|
+
}
|
161
|
+
|
162
|
+
/*
|
163
|
+
返回一个promise, 只有当数组中所有promise都成功才成功, 否则失败
|
164
|
+
*/
|
165
|
+
Promise.all = function (promises) {
|
166
|
+
return new Promise((resolve, reject) => {
|
167
|
+
|
168
|
+
let resolvedCount = 0 // 已经成功的数量
|
169
|
+
const values = new Array(promises.length) // 用来保存成功promise的value值
|
170
|
+
// 遍历所有promise, 取其对应的结果
|
171
|
+
promises.forEach((p, index) => {
|
172
|
+
p.then(
|
173
|
+
value => {
|
174
|
+
resolvedCount++
|
175
|
+
values[index] = value
|
176
|
+
if (resolvedCount === promises.length) { // 都成功了
|
177
|
+
resolve(values)
|
178
|
+
}
|
179
|
+
},
|
180
|
+
reason => reject(reason)
|
181
|
+
)
|
182
|
+
})
|
183
|
+
})
|
184
|
+
}
|
185
|
+
|
186
|
+
/*
|
187
|
+
返回一个promise, 由第一个完成promise决定
|
188
|
+
*/
|
189
|
+
Promise.race = function (promises) {
|
190
|
+
return new Promise((resolve, reject) => {
|
191
|
+
// 遍历所有promise, 取其对应的结果
|
192
|
+
promises.forEach(p => {
|
193
|
+
// 返回的promise由第一个完成p来决定其结果
|
194
|
+
p.then(resolve, reject)
|
195
|
+
})
|
196
|
+
})
|
197
|
+
}
|
198
|
+
|
199
|
+
/*
|
200
|
+
返回一个延迟指定时间才成功(也可能失败)的promise
|
201
|
+
*/
|
202
|
+
Promise.resolveDelay = function (value, time) {
|
203
|
+
return new Promise((resolve, reject) => {
|
204
|
+
setTimeout(() => {
|
205
|
+
// 如果value是一个promise, 最终返回的promise的结果由value决定
|
206
|
+
if (value instanceof Promise) {
|
207
|
+
value.then(resolve, reject)
|
208
|
+
} else { // value不是promise, 返回的是成功的promise, 成功的值就是value
|
209
|
+
resolve(value)
|
210
|
+
}
|
211
|
+
}, time)
|
212
|
+
})
|
213
|
+
}
|
214
|
+
|
215
|
+
/*
|
216
|
+
返回一个延迟指定时间才失败的promise
|
217
|
+
*/
|
218
|
+
Promise.rejectDelay = function (reason, time) {
|
219
|
+
return new Promise((resolve, reject) => {
|
220
|
+
setTimeout(() => {
|
221
|
+
reject(reason)
|
222
|
+
}, time)
|
223
|
+
})
|
224
|
+
}
|
225
|
+
|
226
|
+
export default Promise
|
@@ -0,0 +1,95 @@
|
|
1
|
+
/*
|
2
|
+
自定义消息订阅与发布
|
3
|
+
*/
|
4
|
+
|
5
|
+
const PubSub = {}
|
6
|
+
/*
|
7
|
+
{
|
8
|
+
add: {
|
9
|
+
token1: callback1,
|
10
|
+
token2: callback2
|
11
|
+
},
|
12
|
+
update: {
|
13
|
+
token3: callback3
|
14
|
+
}
|
15
|
+
}
|
16
|
+
*/
|
17
|
+
let callbacksObj = {} // 保存所有回调的容器
|
18
|
+
let id = 0 // 用于生成token的标记
|
19
|
+
|
20
|
+
// 1. 订阅消息
|
21
|
+
PubSub.subscribe = function (msgName, callback) {
|
22
|
+
|
23
|
+
// 确定token
|
24
|
+
const token = 'token_' + ++id
|
25
|
+
// 取出当前消息对应的callbacks
|
26
|
+
const callbacks = callbacksObj[msgName]
|
27
|
+
if (!callbacks) {
|
28
|
+
callbacksObj[msgName] = {
|
29
|
+
[token]: callback
|
30
|
+
}
|
31
|
+
} else {
|
32
|
+
callbacks[token] = callback
|
33
|
+
}
|
34
|
+
// 返回token
|
35
|
+
return token
|
36
|
+
}
|
37
|
+
|
38
|
+
|
39
|
+
// 2. 发布异步的消息
|
40
|
+
PubSub.publish = function (msgName, data) {
|
41
|
+
// 取出当前消息对应的callbacks
|
42
|
+
let callbacks = callbacksObj[msgName]
|
43
|
+
// 如果有值
|
44
|
+
if (callbacks) {
|
45
|
+
// callbacks = Object.assign({}, callbacks)
|
46
|
+
// 启动定时器, 异步执行所有的回调函数
|
47
|
+
setTimeout(() => {
|
48
|
+
Object.values(callbacks).forEach(callback => {
|
49
|
+
callback(data)
|
50
|
+
})
|
51
|
+
}, 0)
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
// 3. 发布同步的消息
|
56
|
+
PubSub.publishSync = function (msgName, data) {
|
57
|
+
// 取出当前消息对应的callbacks
|
58
|
+
const callbacks = callbacksObj[msgName]
|
59
|
+
// 如果有值
|
60
|
+
if (callbacks) {
|
61
|
+
// 立即同步执行所有的回调函数
|
62
|
+
Object.values(callbacks).forEach(callback => {
|
63
|
+
callback(data)
|
64
|
+
})
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|
68
|
+
/*
|
69
|
+
4. 取消消息订阅
|
70
|
+
1). 没有传值, flag为undefined
|
71
|
+
2). 传入token字符串
|
72
|
+
3). msgName字符串
|
73
|
+
*/
|
74
|
+
PubSub.unsubscribe = function (flag) {
|
75
|
+
// 如果flag没有指定或者为null, 取消所有
|
76
|
+
if (flag === undefined) {
|
77
|
+
callbacksObj = {}
|
78
|
+
} else if (typeof flag === 'string') {
|
79
|
+
if (flag.indexOf('token_') === 0) { // flag是token
|
80
|
+
// 找到flag对应的callbacks
|
81
|
+
const callbacks = Object.values(callbacksObj).find(callbacks => callbacks.hasOwnProperty(flag))
|
82
|
+
// 如果存在, 删除对应的属性
|
83
|
+
if (callbacks) {
|
84
|
+
delete callbacks[flag]
|
85
|
+
}
|
86
|
+
} else { // flag是msgName
|
87
|
+
delete callbacksObj[flag]
|
88
|
+
}
|
89
|
+
|
90
|
+
} else {
|
91
|
+
throw new Error('如果传入参数, 必须是字符串类型')
|
92
|
+
}
|
93
|
+
}
|
94
|
+
|
95
|
+
export default PubSub
|
@@ -0,0 +1,28 @@
|
|
1
|
+
/*
|
2
|
+
1. 字符串倒序: reverseString(str) 生成一个倒序的字符串
|
3
|
+
2. 字符串是否是回文: palindrome(str) 如果给定的字符串是回文,则返回 true ;否则返回 false
|
4
|
+
3. 截取字符串: truncate(str, num) 如果字符串的长度超过了num, 截取前面num长度部分, 并以...结束
|
5
|
+
*/
|
6
|
+
|
7
|
+
/*
|
8
|
+
1. 字符串倒序: reverseString(str) 生成一个倒序的字符串
|
9
|
+
*/
|
10
|
+
export function reverseString(str) {
|
11
|
+
// return str.split('').reverse().join('')
|
12
|
+
// return [...str].reverse().join('')
|
13
|
+
return Array.from(str).reverse().join('')
|
14
|
+
}
|
15
|
+
|
16
|
+
/*
|
17
|
+
2. 字符串是否是回文: palindrome(str) 如果给定的字符串是回文,则返回 true ;否则返回 false
|
18
|
+
*/
|
19
|
+
export function palindrome(str) {
|
20
|
+
return str === reverseString(str)
|
21
|
+
}
|
22
|
+
|
23
|
+
/*
|
24
|
+
3. 截取字符串: truncate(str, num) 如果字符串的长度超过了num, 截取前面num长度部分, 并以...结束
|
25
|
+
*/
|
26
|
+
export function truncate(str, num) {
|
27
|
+
return str.length > num ? str.slice(0, num) + '...' : str
|
28
|
+
}
|
@@ -0,0 +1,47 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="UTF-8">
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6
|
+
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
7
|
+
<title>函数的call/apply/bind()</title>
|
8
|
+
</head>
|
9
|
+
<body>
|
10
|
+
|
11
|
+
<!--
|
12
|
+
1. 区别call()/apply()/bind()
|
13
|
+
call(obj)/apply(obj): 调用函数, 指定函数中的this为第一个参数的值
|
14
|
+
bind(obj): 返回一个新的函数, 新函数内部会调用原来的函数, 且this为bind()指定的第一参数的值
|
15
|
+
注意: 如果obj是null/undefined, this为window
|
16
|
+
2. 应用
|
17
|
+
call()/bind()应用: 根据伪数组生成真数组
|
18
|
+
bind(): react中组件的自定义方法 / vue中的事件回调函数内部
|
19
|
+
3. 自定义call()/apply()
|
20
|
+
1). 给obj添加一个临时方法, 方法名任意, 值为当前函数
|
21
|
+
2). 通过obj调用这个临时方法, 并将接收的参数传入
|
22
|
+
3). 删除obj上的这个临时方法属性
|
23
|
+
4. 自定义实现bind()
|
24
|
+
1). 返回一个新函数
|
25
|
+
2). 在新函数内部通过原函数对象的call方法来执行原函数
|
26
|
+
指定this为obj
|
27
|
+
指定参数为bind调用的参数和后面新函数调用的参数
|
28
|
+
-->
|
29
|
+
|
30
|
+
<script src="../dist/atguigu-utils.js"></script>
|
31
|
+
<script>
|
32
|
+
function fn(a, b) {
|
33
|
+
console.log(a, b, this)
|
34
|
+
}
|
35
|
+
|
36
|
+
const obj = {m: 1}
|
37
|
+
|
38
|
+
aUtils.call(fn, obj, 2, 3) // 相当于执行了obj.fn(2, 3)
|
39
|
+
aUtils.apply(fn, obj, [2, 3])
|
40
|
+
aUtils.call(fn, undefined, 2, 3)
|
41
|
+
|
42
|
+
aUtils.bind(fn, obj)(2, 3)
|
43
|
+
aUtils.bind(fn, obj, 4)(2, 3)
|
44
|
+
aUtils.bind(fn, undefined, 4)(2, 3)
|
45
|
+
</script>
|
46
|
+
</body>
|
47
|
+
</html>
|
@@ -0,0 +1,54 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="UTF-8">
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6
|
+
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
7
|
+
<title>函数节流与防抖</title>
|
8
|
+
</head>
|
9
|
+
<body>
|
10
|
+
|
11
|
+
<button id="throttle">测试函数节流</button>
|
12
|
+
<button id="debounce">测试函数防抖</button>
|
13
|
+
|
14
|
+
<!--
|
15
|
+
1. 事件频繁触发可能造成的问题?
|
16
|
+
1). 一些浏览器事件:window.onresize、window.mousemove等,触发的频率非常高,会造成浏览器性能问题
|
17
|
+
2). 如果向后台发送请求,频繁触发,对服务器造成不必要的压力
|
18
|
+
|
19
|
+
2. 如何限制事件处理函数频繁调用
|
20
|
+
1). 函数节流
|
21
|
+
2). 函数防抖
|
22
|
+
|
23
|
+
3. 函数节流(throttle)
|
24
|
+
1). 理解:
|
25
|
+
在函数需要频繁触发时: 函数执行一次后,只有大于设定的执行周期后才会执行第二次
|
26
|
+
适合多次事件按时间做平均分配触发
|
27
|
+
2). 场景:
|
28
|
+
窗口调整(resize)
|
29
|
+
页面滚动(scroll)
|
30
|
+
DOM 元素的拖拽功能实现(mousemove)
|
31
|
+
抢购疯狂点击(click)
|
32
|
+
|
33
|
+
4. 函数防抖(debounce)
|
34
|
+
1). 理解:
|
35
|
+
在函数需要频繁触发时: 在规定时间内,只让最后一次生效,前面的不生效。
|
36
|
+
适合多次事件一次响应的情况
|
37
|
+
2). 场景:
|
38
|
+
输入框实时搜索联想(keyup/input)
|
39
|
+
-->
|
40
|
+
|
41
|
+
<script src="../dist/atguigu-utils.js"></script>
|
42
|
+
<script>
|
43
|
+
/* 处理点击事件的回调函数 */
|
44
|
+
function handleClick(event) { // 处理事件的回调
|
45
|
+
console.log('处理点击事件', this, event)
|
46
|
+
}
|
47
|
+
|
48
|
+
// document.getElementById('throttle').onclick = handleClick
|
49
|
+
document.getElementById('throttle').onclick = aUtils.throttle(handleClick, 2000)
|
50
|
+
document.getElementById('debounce').onclick = aUtils.debounce(handleClick, 2000)
|
51
|
+
</script>
|
52
|
+
|
53
|
+
</body>
|
54
|
+
</html>
|
Binary file
|
@@ -0,0 +1,51 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="UTF-8">
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6
|
+
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
7
|
+
<title>数组声明式方法</title>
|
8
|
+
</head>
|
9
|
+
<body>
|
10
|
+
<script src="../dist/atguigu-utils.js"></script>
|
11
|
+
<script>
|
12
|
+
/*
|
13
|
+
自定义实现一组数组声明式方法
|
14
|
+
1). map()
|
15
|
+
2). reduce()
|
16
|
+
3). filter()
|
17
|
+
4). find()
|
18
|
+
5). findIndex()
|
19
|
+
6). every()
|
20
|
+
7). some()
|
21
|
+
*/
|
22
|
+
/*
|
23
|
+
需求:
|
24
|
+
1. 产生一个每个元素都比原来大10的新数组
|
25
|
+
2. 得到所有奇数的和
|
26
|
+
3. 得到值大于8且下标是偶数位的元素组成的数组
|
27
|
+
4. 找出一个值大于8且下标是偶数位的元素
|
28
|
+
5. 找出一个值大于8且下标是偶数位的元素的下标
|
29
|
+
6. 判断下标为偶数的元素是否都为奇数
|
30
|
+
7. 判断是否有下标为偶数的元素值为奇数
|
31
|
+
*/
|
32
|
+
|
33
|
+
const arr = [1, 3, 6, 9, 15, 19, 16]
|
34
|
+
|
35
|
+
console.log(aUtils.map(arr, (item, index) => item + 10))
|
36
|
+
console.log(aUtils.reduce(arr, (preTotal, item, index) => {
|
37
|
+
return preTotal + (item%2===1 ? item : 0)
|
38
|
+
}, 0))
|
39
|
+
console.log(aUtils.filter(arr, (item, index) => item>8 && index%2===0))
|
40
|
+
console.log(aUtils.find(arr, (item, index) => item>8 && index%2===0))
|
41
|
+
console.log(aUtils.findIndex(arr, (item, index) => item>8 && index%2===0))
|
42
|
+
console.log(aUtils.every(arr, (item, index) => index%2===1 || item%2===1))
|
43
|
+
console.log(aUtils.some(arr, (item, index) => index%2===1 || item%2===1))
|
44
|
+
aUtils.test()
|
45
|
+
</script>
|
46
|
+
|
47
|
+
<script>
|
48
|
+
|
49
|
+
</script>
|
50
|
+
</body>
|
51
|
+
</html>
|