1.防抖 debounce
防抖的原理:你尽管触发事件,但是我一定在事件触发的 n 秒之后才执行,如果你在触发事件 n 秒内又触发了这个事件,那我就以新的事件的时间为准,n 秒之后在执行。
1 2 3 4 5 6 7 8 9 10 11 function debounce (func, delay ) { let timer; return function (...args ) { if (timer) clearTimeout (timer); timer = setTimeout (() => { func.apply (this , args); timer = null ; }, delay); }; }
2.节流 throttle
节流的原理:如果你持续触发事件,没隔一段时间,只会执行一次事件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 function throttle (func, delay ) { let previous = 0 ; return function (...args ) { let now = +new Date (); if (now - previous > delay) { func.apply (this , args); previous = now; } }; } function throttle (func, delay ) { let timer; return function (...args ) { if (timer) return ; timer = setTimeout (() => { func.apply (this , args); timer = null ; }, delay); }; }
两者的区别在于: 防抖:
1 if (timer) clearTimeout (timer);
节流:
3.函数柯里化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 function add (a, b, c ) { return a + b + c; } add (1 , 2 , 3 );let addCurry = curry (add);addCurry (1 )(2 )(3 );function curry (fn ) { let judge = (...args1 ) => { if (args1.length == fn.length ) return fn (...args1); return (...args2 ) => judge (...args1, ...args2); }; return judge; }
4.偏函数
1 2 3 4 5 6 7 8 9 10 11 function add (a, b, c ) { return a + b + c; } let partialAdd = partial (add, 1 );partialAdd (2 , 3 );function partial (fn, ...args1 ) { return (...args2 ) => { return fn (...args1, ...args2); }; }
5.instanceof
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 function myInstanceof (L = null , R ) { if (Object (L) !== L) return false ; if (typeof R !== "function" || !R.prototype ) throw new TypeError ("Right-hand side of " instanceof " is not an object" ); let link = L.__proto__ ; while (link !== null ) { if (link === R.prototype ) return true ; link = link.__proto__ ; } return false ; }
6.new
1 2 3 4 5 6 7 8 9 10 11 let newObj = myNew (Fn , "Leo" , 18 );function myNew (Fn ) { if (typeof Fn !== "function" ) throw new TypeError ("This is not a constructor" ); var args = Array .from (arguments ).slice (1 ); var obj = {}; obj.__proto__ = Fn .prototype ; var res = Fn .call (obj, ...args); return Object (res) === res ? res : obj; }
7.浅拷贝 深拷贝
浅拷贝:对于复杂数据类型而言,复制了一份栈内存中的地址。
深拷贝:对于复杂数据类型而言,开辟了一块新的堆内存并且在栈内存里得到一份新的指向地址。新旧数据改变互不影响。对于简单数据类型而言,复制了一份栈内存中的 value。
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 const getType = (data ) => { return Object .prototype .toString .call (data).slice (8 , -1 ); }; const isObject = (data ) => { return ( (typeof data === "object" && data !== null ) || getType (data) === "Function" ); }; const cloneDeep = (data, hash = new WeakMap () ) => { if (!isObject (data)) return data; const targetType = getType (data); if (hash.has (data)) return hash.get (data); if (targetType === "Function" ) { return function ( ) { return data.call (this , ...arguments ); }; } if (targetType === "RegExp" ) { const reg = new RegExp (data.source , data.flags ); if (data.flags ) { reg.lastIndex = 0 ; } return reg; } if (targetType === "Date" ) return new Date (data); if (targetType === "Set" ) { const newSetTarget = new Set (); data.forEach ((v ) => { newSetTarget.add (v); }); return newSetTarget; } if (targetType === "Map" ) { const newMapTarget = new Map (); data.forEach ((v, k ) => { if (isObject (v)) { newMapTarget.set (k, cloneDeep (v)); } else { newMapTarget.set (k, v); } }); return newMapTarget; } if (targetType === "Symbol" ) return Object (Symbol .prototype .valueOf .call (data)); let copiedData = targetType === "Array" ? [] : {}; hash.set (data, copiedData); for (let key in data) { if (data.hasOwnProperty (key)) { if (isObject (data[key])) { copiedData[key] = cloneDeep (data[key], hash); } else { copiedData[key] = data[key]; } } } return copiedData; };
8.数组去重
1 2 3 4 5 6 7 8 9 10 function unique (arr ) { var res = arr.filter (function (item, index, array ) { return array.indexOf (item) === index; }); return res; } var unique = (arr ) => [...new Set (arr)];
9.数组扁平化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function flatten (arr ) { var result = []; for (var i = 0 , len = arr.length ; i < len; i++) { if (Array .isArray (arr[i])) { result = result.concat (flatten (arr[i])); } else { result.push (arr[i]); } } return result; } function flatten (arr ) { while (arr.some ((item ) => Array .isArray (item))) { arr = [].concat (...arr); } return arr; }
10.发布订阅模式
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 class EventEmitter { constructor ( ) { this .cache = {}; } on (name, fn ) { if (this .cache [name]) { this .cache [name].push (fn); } else { this .cache [name] = [fn]; } } off (name, fn ) { let tasks = this .cache [name]; if (tasks) { const index = tasks.findIndex ((f ) => f === fn || f.callback === fn); if (index >= 0 ) { tasks.splice (index, 1 ); } } } emit (name, once = false , ...args ) { if (this .cache [name]) { let tasks = this .cache [name].slice (); for (let fn of tasks) { fn (...args); } if (once) { delete this .cache [name]; } } } } let eventBus = new EventEmitter ();let fn1 = function (name, age ) { console .log (`${name} ${age} ` ); }; let fn2 = function (name, age ) { console .log (`hello, ${name} ${age} ` ); }; eventBus.on ("aaa" , fn1); eventBus.on ("aaa" , fn2); eventBus.emit ("aaa" , false , "布兰" , 12 );