工具函数 防抖与节流 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 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 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; } } } 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 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; } }
Promise Promise 构造函数 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 = []; 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 ( ) {}; } 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); } }); } 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); } }); }); } } }
Polyfill Promise.all()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 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) ); }); }); }
Promise 并发限制 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 async function asyncPool (limit, arr, fetch ) { const pending = []; const results = []; let index = 0 ; async function push ( ) { if (index >= arr.length ) { return ; } const p = fetch (arr[index]); pending.push (p); results.push (p); 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); }
原生 API bind()
1 2 3 4 5 6 Function .prototype .bind = function (...args ) { const func = this ; const ctx = args[0 ]; const params = args.slice (1 ); return (...args ) => func.apply (ctx, [...params, ...args]); };
instanceof
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); } }
new
JavaScript - 模拟实现 new
reduce()
实现 map()
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; };
语言特性 Iterable 对象 1 2 3 4 5 6 7 8 9 10 11 12 13 14 const object = { a : 1 , b : 2 , c : 3 , *[Symbol .iterator ]() { for (const key of Object .keys (this )) { yield this [key]; } }, }; console .log (...object); object.d = 4 ; console .log (...object);
LazyMan (事件循环) 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' ); class LazyMan { constructor (name ) { this .taskList = []; console .log (`Hi I am ${name} ` ); 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 ; } }