警告
本文最后更新于 2019-07-17,文中内容可能已过时。
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
| /**
* 防抖:仅执行一次
*/
const debounce = <F extends (...args: any[]) => any>(func: F, delay = 300) => {
let timer: number | null = null;
const ret = (...args: any) => {
if (timer) {
window.clearTimeout(timer);
}
timer = window.setTimeout(() => {
func(...args);
timer = null;
}, delay);
};
return ret as (...args: Parameters<F>) => void;
};
element.onclick = debounce(myFunc);
/**
* 节流:限制最小执行间隔
*/
const throttle = <F extends (...args: any[]) => any>(func: F, delay = 300) => {
let timer: number | null = null;
const ret = (...args: any) => {
if (!timer) {
timer = window.setTimeout(() => {
func(...args);
timer = null;
}, delay);
}
};
return ret as (...args: Parameters<F>) => void;
};
window.onresize = throttle(myFunc);
|
将一个函数从可调用的 f(a, b, c)
转换为可调用的 f(a)(b)(c)
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| /**
* @param {Function} func
* @return {Function}
*/
function curry(func) {
return function curried(...args) {
if (args.length >= func.length) {
return func.apply(this, args);
} else {
return function (...args2) {
return curried.apply(this, [...args, ...args2]);
};
}
};
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| // 标准递归
function flatten(arr) {
return arr.reduce((pre, cur) => {
return pre.concat(Array.isArray(cur) ? flatten(cur) : cur);
}, []);
}
// 字符串分割
function flatten(arr) {
return Array.prototype.toString
.call(arr)
.split(',')
.map((val) => Number(val));
}
// 重复扩展直至扁平
function flatten(arr) {
while (arr.some((val) => Array.isArray(val))) {
arr = [...arr];
}
return arr;
}
|
输入:
1
2
3
4
5
6
| {
a: 1,
b: [1, 2, { c: true }, [3]],
d: { e: 2, f: 3 },
g: null,
}
|
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
| /**
* @param {Array} input
* @param {string} name
* @param {Object} res
*/
function _flatten(input, name, res) {
for (let key of Object.keys(input)) {
let baseName = name;
const val = input[key];
if (val === null || val === undefined) {
continue;
}
if (/^[0-9]/.exec(`${key}`)) {
baseName += `[${key}]`;
} else if (baseName === '') {
baseName += `${key}`;
} else {
baseName += `.${key}`;
}
if (typeof val === 'object') {
_flatten(val, baseName, res);
} else {
res[baseName] = val;
}
}
}
/**
* @param {Array} input
* @return {Object}
*/
function flatten(input) {
const res = {};
_flatten(input, '', res);
return res;
}
|
1
2
3
4
| Array.prototype.unique = function () {
const arr = this;
return arr.filter((val, idx) => arr.indexOf(val) === idx);
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| // 可以通过 WeakMap 解决循环引用问题,同时保证内存被回收
const map = new WeakMap();
function cloneDeep(src) {
if (src && typeof src === 'object') {
if (map.has(src)) {
return map.get(src);
} else {
map.set(src, src);
}
const ret = Array.isArray(src) ? [] : {};
for (let key of Object.keys(src)) {
ret[key] = cloneDeep(src[key]);
}
return ret;
} else {
return src;
}
}
|
Promises/A+ 标准中仅指定了 Promise 对象的 then 方法的行为,其它一切我们常见的方法、函数都并没有指定。
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
| class Promise {
constructor(func) {
// 初始化状态
const self = this;
this.status = 'pending';
this.data = undefined;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
// API 函数
function resolve(value) {
if (self.status === 'pending') {
self.status = 'resolved';
self.data = value;
self.onResolvedCallbacks.forEach((func) => {
func();
});
}
}
function reject(reason) {
if (self.status === 'pending') {
self.status = 'rejected';
self.data = reason;
self.onRejectedCallbacks.forEach((func) => {
func();
});
}
}
// 执行同步构造器
try {
func(resolve, reject);
} catch (e) {
reject(e);
}
}
then(onResolved, onRejected) {
// 检查参数
if (typeof onResolved !== 'function') {
onResolved = function () {};
}
if (typeof onRejected !== 'function') {
onRejected = function () {};
}
// resolve 或 reject 则执行对应回调
if (this.status === 'resolved') {
return new Promise((resolve, reject) => {
try {
resolve(onResolved(this.data));
} catch (e) {
reject(e);
}
});
}
if (this.status === 'rejected') {
return new Promise((resolve, reject) => {
try {
resolve(onRejected(this.data));
} catch (e) {
reject(e);
}
});
}
// pending 状态则等待 pending 完成
if (this.status === 'pending') {
return new Promise((resolve, reject) => {
this.onResolvedCallbacks.push(() => {
try {
resolve(onResolved(this.data));
} catch (e) {
reject(e);
}
});
this.onRejectedCallbacks.push(() => {
try {
resolve(onRejected(this.data));
} catch (e) {
reject(e);
}
});
});
}
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| /**
* @param {Array} arr
* @return {Promise<any[]>}
*/
function promiseAll(arr) {
return new Promise((resolve, reject) => {
let pending = arr.length;
const results = new Array(arr.length);
arr.forEach((p, idx) => {
p.then(
(res) => {
results[idx] = res;
if (--pending === 0) {
resolve(results);
}
},
(e) => reject(e)
);
});
});
}
|
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
| /**
* @param {number} limit
* @param {Array} arr
* @param {Function} fetch
* @return {Promise<any[]>}
*/
async function asyncPool(limit, arr, fetch) {
const pending = [];
const results = [];
let index = 0; // 入池用下标
// 入池一个
async function push() {
// 若已经全部进入池子则等待全部完成
if (index >= arr.length) {
return;
}
// 获得一个 Promise
const p = fetch(arr[index]);
pending.push(p);
results.push(p);
// Promise 完成后在 pending 中删除
p.then(() => pending.splice(pending.indexOf(p), 1));
if (pending.length >= limit) {
await Promise.race(pending);
}
index++;
await push();
}
await push();
return await Promise.all(results);
}
|
1
2
3
4
5
6
| Function.prototype.bind = function (...args) {
const func = this; // 需要绑定的函数
const ctx = args[0]; // 绑定的 this
const params = args.slice(1); // bind 时传入的参数
return (...args) => func.apply(ctx, [...params, ...args]);
};
|
1
2
3
4
5
6
7
8
9
10
11
12
| function instanceOf(inst, func) {
let proto = Object.getPrototypeOf(inst);
while (true) {
if (!proto) {
return false;
}
if (proto === func.prototype) {
return true;
}
proto = Object.getPrototypeOf(proto);
}
}
|
JavaScript - 模拟实现 new
1
2
3
4
5
6
7
8
| Array.prototype.mapPolyfill = function (func, thisValue) {
const self = thisValue || this;
const ret = [];
this.reduce((pre, cur, idx, arr) => {
return ret.push(func.call(self, cur, idx, arr));
}, ret);
return ret;
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| const object = {
a: 1,
b: 2,
c: 3,
// 本质是一个 Generator 函数
*[Symbol.iterator]() {
for (const key of Object.keys(this)) {
yield this[key];
}
},
};
console.log(...object); // 1 2 3
object.d = 4;
console.log(...object); // 1 2 3 4
|
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
| new LazyMan('Tony')
.eat('lunch')
.eat('dinner')
.sleepFirst(5)
.sleep(10)
.eat('junk food');
// Hi I am Tony
// 等待了5秒...
// I am eating lunch
// I am eating dinner
// 等待了10秒...
// I am eating junk food
class LazyMan {
constructor(name) {
this.taskList = [];
console.log(`Hi I am ${name}`);
// 等待第一次事件循环
// 即 tasklist 初始化完成
setTimeout(() => {
this.next();
}, 0);
}
next() {
const func = this.taskList.shift();
func && func();
}
eat(food) {
const func = () => {
console.log(`I am eating ${food}`);
this.next();
};
this.taskList.push(func);
return this;
}
sleepFirst(time) {
const func = () => {
setTimeout(() => {
console.log(`等待了${time}秒...`);
this.next();
}, time * 1000);
};
this.taskList.unshift(func);
return this;
}
sleep(time) {
const func = () => {
setTimeout(() => {
console.log(`等待了${time}秒...`);
this.next();
}, time * 1000);
};
this.taskList.push(func);
return this;
}
}
|