手写JS常用方法
# 判断数据类型
function type(obj) {
return Object.prototype.toString.call(obj).match(/\[object (.*?)\]/)[1]
}
console.log(type('')) // String*
console.log(type(123)) // Number*
console.log(type(true)) // Boolean*
console.log(type(undefined)) // Undefined*
console.log(type(null)) // Null
console.log(type({})) // Object
console.log(type([])) // Array
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 两个数组交叉对比求交集和差集
ES6 中使用 Set 结构:
let a = new Set([1, 2, 3]);
let b = new Set([3, 5, 2]);
// 并集
let unionSet = new Set([...a, ...b]);
//[1,2,3,5]
// 交集
let intersectionSet = new Set([...a].filter(x => b.has(x)));
// [2,3]
// ab差集
let differenceABSet = new Set([...a].filter(x => !b.has(x)));
// [1]
再把Set转换为数组即可.let arr = Array.from(set);
// 或 let arr = [...set];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 函数柯里化
其实就是将使用多个参数的函数转换成一系列使用一个参数的函数的技术
function add(a, b, c) {
return a + b + c
}
add(1, 2, 3)
let addCurry = curry(add)
addCurry(1)(2)(3)
1
2
3
4
5
6
2
3
4
5
6
现在就是要实现 curry 这个函数,使函数从一次调用传入多个参数变成多次调用每次传一个参数。
function curry(fn) {
let judge = (...args) => {
if (args.length == fn.length) return fn(...args)
return (...arg) => judge(...args, ...arg)
}
return judge
}
1
2
3
4
5
6
7
2
3
4
5
6
7
# 数字精度处理
/**
* 保留精度
* @param value 值
* @param precision 精度:2代表两位小数
* @param multiplyer 乘数:100代表乘以100倍
* @returns 返回保留精度的小数
*/
export const precise = (
value: number,
precision: number = 0,
multiplyer = 1
) => {
const ratio = Math.pow(10, precision)
return Math.round(value * multiplyer * ratio) / ratio
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 判断图片能不能访问
function checkImg(imgUrl) {
return new Promise(function(resolve, reject) {
var ImgObj = new Image()
ImgObj.src = imgUrl
ImgObj.onload = function(res) {
resolve(res)
}
ImgObj.onerror = function(err) {
reject(err)
}
})
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 数组去重
// 数组去重1
function deduplicationArr(arr) {
return arr.filter((item, index) => {
return arr.indexOf(item) === index
})
}
obj1 = {
name: 111
}
let arr = [obj1, 1, 4, 524, 5, 64, 6, 24, 51, 324, 26, 3, 1, 33, 4, obj1]
console.log(deduplicationArr(arr)) // [ { name: 111 }, 1, 4, 524, 5, 64, 6, 24, 51, 324, 26, 3, 33 ]
// 数组去重2
console.log([...new Set(arr)]) // [ { name: 111 }, 1, 4, 524, 5, 64, 6, 24, 51, 324, 26, 3, 33 ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 深拷贝
简单版本
function deepClone(obj) {
if (typeof obj !== 'object') return obj // 普通类型,直接返回
if (obj === null || obj === undefined) return obj
if (obj instanceof Date) return new Date(obj)
if (obj instanceof RegExp) return new RegExp(obj)
const res = new obj.constructor()
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
res[key] = deepClone(obj[key])
}
}
return res
}
console.log(deepClone({ name: 111, arr: [12, 5452, 3245, { name: 22 }] }))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
完善版本:
利用 Object.prototype.toString.call(obj) 获取对象的准确类型
对每种类型单独处理
const mapTag = '[object Map]'
const setTag = '[object Set]'
const arrayTag = '[object Array]'
const objectTag = '[object Object]'
const argsTag = '[object Arguments]'
const boolTag = '[object Boolean]'
const dateTag = '[object Date]'
const numberTag = '[object Number]'
const stringTag = '[object String]'
const symbolTag = '[object Symbol]'
const errorTag = '[object Error]'
const regexpTag = '[object RegExp]'
const funcTag = '[object Function]'
const deepTag = [mapTag, setTag, arrayTag, objectTag, argsTag]
function forEach(array, iteratee) {
let index = -1
const length = array.length
while (++index < length) {
iteratee(array[index], index)
}
return array
}
function isObject(target) {
const type = typeof target
return target !== null && (type === 'object' || type === 'function')
}
function getType(target) {
return Object.prototype.toString.call(target)
}
function getInit(target) {
const Ctor = target.constructor
return new Ctor()
}
function cloneSymbol(targe) {
return Object(Symbol.prototype.valueOf.call(targe))
}
function cloneReg(targe) {
const reFlags = /\w*$/
const result = new targe.constructor(targe.source, reFlags.exec(targe))
result.lastIndex = targe.lastIndex
return result
}
function cloneFunction(func) {
const bodyReg = /(?<={)(.|\n)+(?=})/m
const paramReg = /(?<=\().+(?=\)\s+{)/
const funcString = func.toString()
if (func.prototype) {
const param = paramReg.exec(funcString)
const body = bodyReg.exec(funcString)
if (body) {
if (param) {
const paramArr = param[0].split(',')
return new Function(...paramArr, body[0])
} else {
return new Function(body[0])
}
} else {
return null
}
} else {
return eval(funcString)
}
}
function cloneOtherType(targe, type) {
const Ctor = targe.constructor
switch (type) {
case boolTag:
case numberTag:
case stringTag:
case errorTag:
case dateTag:
return new Ctor(targe)
case regexpTag:
return cloneReg(targe)
case symbolTag:
return cloneSymbol(targe)
case funcTag:
return cloneFunction(targe)
default:
return null
}
}
function clone(target, map = new WeakMap()) {
// 克隆原始类型
if (!isObject(target)) {
return target
}
// 初始化
const type = getType(target)
let cloneTarget
if (deepTag.includes(type)) {
cloneTarget = getInit(target, type)
} else {
return cloneOtherType(target, type)
}
// 防止循环引用
if (map.get(target)) {
return map.get(target)
}
map.set(target, cloneTarget)
// 克隆set
if (type === setTag) {
target.forEach((value) => {
cloneTarget.add(clone(value, map))
})
return cloneTarget
}
// 克隆map
if (type === mapTag) {
target.forEach((value, key) => {
cloneTarget.set(key, clone(value, map))
})
return cloneTarget
}
// 克隆对象和数组
const keys = type === arrayTag ? undefined : Object.keys(target)
forEach(keys || target, (value, key) => {
if (keys) {
key = value
}
cloneTarget[key] = clone(target[key], map)
})
return cloneTarget
}
module.exports = {
clone
}
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
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
# 扁平化数组
function flatten(arr) {
if (!arr || arr.length === 0) return arr
let res = []
for (let i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
res = res.concat(flatten(arr[i]))
} else {
res.push(arr[i])
}
}
return res
}
const res = flatten([111, [222, { name: '000' }, [52452345, { name: 111 }]]])
console.log(res)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 发布订阅者模式
class EventEmitter {
constructor() {
this.events = {}
}
on(eventName, fn) {
if (this.events[eventName]) {
this.events[eventName].push(fn)
} else {
this.events[eventName] = [fn]
}
}
once(eventName, fn) {
let that = this
let func = function(args) {
fn.call(this, args)
that.off(eventName, func)
}
this.on(eventName, func)
}
emit(eventName, ...args) {
if (this.events[eventName] && this.events[eventName].length > 0) {
this.events[eventName].forEach((fn) => {
fn.call(this, ...args)
})
}
}
off(eventName, fn) {
if (this.events[eventName]) {
let index = this.events[eventName].findIndex((func) => {
return fn === func
})
if (index >= 0) {
this.events[eventName].splice(index, 1)
}
}
}
}
let bus = new EventEmitter()
let test111 = function(text) {
console.log(text, '111')
}
let test222 = function(text) {
console.log(text, '222')
}
let test333 = function(text) {
console.log(text, '333')
}
bus.on('click', test111)
bus.on('click', test222)
bus.once('click', test333)
bus.emit('click', 'hello1')
bus.off('click', test111)
bus.emit('click', 'hello2')
// hello1 111
// hello1 222
// hello1 333
// hello2 222
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
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
上次更新: 2023/04/05, 09:41:10