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 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 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 (function (window ){ function Promise (executor ){ this .status = 'pending' ; this .data = undefined ; this .callback = []; const resolve = value => { if (this .status !=='pending' ) return ; this .status = 'resolved' ; this .data = value; if (this .callback .length >0 ){ setTimeout (()=> { this .callback .forEach (callbackObj => { callbackObj.onResolved (value); }) }) } } const reject = reason => { if (this .status !=='pending' ) return ; this .status = 'rejected' ; this .data = reason; if (this .callback .length >0 ){ setTimeout (()=> { this .callback .forEach (callbackObj => { callbackObj.onRejected (reason); }) }) } } try { executor (resolve, reject); }catch (err){ reject (err); } } Promise .prototype .then = function (onResolved, onRejected ){ onResolved = typeof onResolved==='function' ?onResolved :value => value; onRejected = typeof onRejected==='function' ?onRejected :reason => {throw reason}; const that = this ; return new Promise ((resolve, reject )=> { function handle (callback ){ try { const res = callback (that.data ); if (res instanceof Promise ) res.then (resolve, reject); else resolve (res); }catch (err){ reject (err); } } if (that.status ==='pending' ){ this .callback .push ({ onResolved ( ){ handle (onResolved); }, onRejected ( ){ handle (onRejected); } }) }else if (that.status ==='resolved' ){ setTimeout (()=> { handle (onResolved); }) }else { setTimeout (()=> { handle (onRejected); }) } }) } Promise .prototype .catch = function (onRejected ){ return this .then (undefined , onRejected); } Promise .prototype .finally = function (callback ){ return this .then ( value => { return Promise .resolve (callback ()).then (()=> value); }, reason => { return Promise .resolve (callback ()).then (()=> {throw reason}); } ) } Promise .resolve = function (value ){ return new Promise ((resolve, reject )=> { if (value instanceof Promise ) value.then (resolve, reject); else resolve (value); }) } Promise .reject = function (reason ){ return new Promise ((resolve, reject )=> { reject (reason); }) } Promise .race = function (promises ){ return new Promise ((resolve, reject )=> { if (promises.length ===0 ) return ; promises.forEach (p => { Promise .resolve (p).then ( value => {resolve (value)}, reason => {reject (reason)} ) }) }) } Promise .all = function (promises ){ let values = new Array (promises.length ); let count = 0 ; return new Promise ((resolve, reject )=> { if (promises.length ===0 ) resolve ([]); promises.forEach ((p, i )=> { Promise .resolve (p).then ( value => { count++; values[i] = value; if (count===promises.length ) resolve (values); }, reason => { reject (reason); } ) }) }) } Promise .allSettled = function (promises ){ let values = new Array (promises.length ); let count = 0 ; return new Promise ((resolve, reject )=> { if (promises.length ===0 ) resolve ([]); promise.forEach ((p, i )=> { Promise .resolve (p).then ( value => { count++; values[i] = { status : 'resolved' , data : value }; if (count===promises.length ) resolve (values); }, reason => { count++; values[i]={ status : 'rejected' , data : reason }; if (count===promises.length ) resolve (values); } ) }) }) } Promise .any = function (promises ){ let count = 0 ; return new Promise ((resolve, reject )=> { if (promises.length ===0 ) resolve ([]); promises.forEach (p => { Promise .resolve (p).then ( value => { resolve (value) }, reason => { count++; if (count===promises.length ) reject (new AggregateError ('promises all fail!' )); } ) }) }) } window .Promise = Promise ; })(window );
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 <script src ="promise.js" > </script > <script > const p1 = Promise .resolve (2 ); const p2 = Promise .resolve (Promise .resolve (3 )); const p3 = Promise .resolve (Promise .reject (4 )); p1.then (value => {console .log ('p1' , value)}) p2.then (value => {console .log ('p2' , value)}) p3.catch (reason => {console .log ('p3' , reason)}) const pAll = Promise .all ([p1, p2]); pAll.then ( values => { console .log ('race onResolved()' , values); }, reason => { console .log ('race onRejected()' , reason); } ) const pRace = Promise .race ([p1, p2, p3]); pRace.then ( value => { console .log ('race onResolved()' , value); }, reason => { console .log ('race onRejected()' , reason); } ) const pAllsettled = Promise .allSettled ([p1, p2, p3]); pAllsettled.then ( values => { console .log ('allsettled' , values); }, reason => { console .log ('allsettled' , reason); } ) const pAny = Promise .any ([p3]); pAny.then ( value => { console .log ('pany resolved' , value); }, reason => { console .log ('pany rejected' , reason); } ) </script >
数组 数组排序算法的时间复杂度:
数组排序 数组排序:冒泡排序 o(n^2)
1 2 3 4 5 6 7 8 9 function bubbleSort (arr ){ const len = arr.length ; for (let i=0 ;i<len;i++) for (let j=0 ;j<len-1 ;j++) if (arr[j]>arr[j+1 ]) [arr[j], arr[j+1 ]] = [arr[j+1 ], arr[j]] return arr; }
数组排序:选择排序 o(n^2)
1 2 3 4 5 6 7 8 9 10 11 12 13 function selectSort (arr ){ const len = arr.length ; let minIndex; for (let i=0 ;i<len-1 ;i++){ minIndex = i; for (let j=i;j<len;j++) if (arr[j]<arr[minIndex]) minIndex = j; if (minIndex!==i) [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]] } return arr; }
数组排序:插入排序 o(n^2)
1 2 3 4 5 6 7 8 9 10 11 12 function insertSort (arr ){ for (let i=1 ;i<arr.length ;i++){ let j=i; let target = arr[j]; while (j>0 &&arr[j-1 ]>target){ arr[j]=arr[j-1 ]; j--; } arr[j] = target; } return arr; }
数组排序:快速排序 o(nlogn-n^2)
1 2 3 4 5 6 7 8 function quickSort (arr ){ if (arr.length <2 ) return arr; let cur = arr[arr.length -1 ]; const left = arr.filter ((v, i )=> v<=cur&&i!==arr.length -1 ); const right = arr.filter (v => v>cur); return [...quickSort (left), cur, ...quickSort (right)]; }
数组排序:归并排序 o(nlogn)
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 function merge (left, right ){ let res = []; let i = 0 ; let j = 0 ; while (i<left.length &&j<right.length ){ if (left[i]<right[j]){ res.push (left[i]); i++; }else { res.push (right[j]); j++; } } if (i<left.length ) res.push (...left.slice (i)); else res.push (...right.slice (j)); return res; } function mergeSort (arr ){ if (arr.length <2 ) return arr; const mid = Math .floor (arr.length /2 ); const left = mergeSort (arr.slice (0 , mid)); const right = mergeSort (arr.slice (mid)); return merge (left, right); }
数组去重 数组去重:双重for+splice
1 2 3 4 5 6 7 8 9 10 function unique (arr ){ for (let i=0 ;i<arr.length ;i++){ for (let j=0 ;j<arr.length ;j++) if (arr[i]===arr[j]){ arr.splice (j, 1 ); j--; } } return arr; }
数组去重:indexOf+新数组
1 2 3 4 5 6 7 8 function unique (arr ){ var res = []; for (let i=0 ;i<arr.length ;i++){ if (res.indexOf (arr[i])===-1 ) res.push (arr[i]); } return res; }
数组去重:快慢指针需要对数组进行排序,会打乱数组顺序
1 2 3 4 5 6 7 8 9 10 11 function unique (arr ){ arr.sort ((a,b )=> a-b); let slow = 1 , fast = 1 ; while (fast < arr.length ){ if (arr[fast]!==arr[fast-1 ]) arr[slow++]=arr[fast] fast++; } arr.length = slow; return arr; }
数组去重:ES6 set
1 2 3 function unique (arr ){ return [...new Set (arr)]; }
数组去重:map
1 2 3 4 5 6 7 8 9 10 11 function unique (arr ){ let map = new Map (); let res = []; for (let i=0 ;i<arr.length ;i++){ if (!map.has (arr[i])){ map.set (arr[i], true ); res.push (arr[i]); } } return res; }
数组去重:filter
1 2 3 4 5 function unique (arr ){ return arr.filter ((item, index, arr )=> { return arr.indexOf (item)===index; }) }
数组去重:reduce
1 2 3 4 5 6 7 8 function unique (arr ){ let res = arr.reduce ((acc, cur )=> { if (!acc.includes (cur)) acc.push (cur); return acc; }, []); return res; }
数组实现 : reduce与indexOf的参数与别的方法不一样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 (function (window ){ function Array ( ){ this .arr = [1 , 2 , 3 ]; return this .arr ; } Array .prototype .forEach = function (callback ){ if (this ===null ||this ===undefined ) throw new TypeError ('cannot read property forEach of null' ); if (Object .prototype .toString .call (callback)!=='[object Function]' ) throw new TypeError ('callback is not a function' ); var _arr = this .arr , thisArg = arguments [1 ]||window ; for (var i=0 ;i<_arr.length ;i++) callback.call (thisArg, _arr[i], i, _arr); } Array .prototype .map = function (callback ){ if (Object .prototype .toString .call (callback)!=='[object Function]' ) throw new TypeError ('callback is not a function' ); let res = []; for (let i=0 ;i<this .arr .length ;i++){ let tempres = callback.call (arguments [1 ]||window , this .arr [i], i, this .arr ); res.push (tempres); } return res; } Array .prototype .reduce = function (callback ){ if (Object .prototype .toString .call (callback)!=='[object Function]' ) throw new TypeError ('callback is not a function' ); var i = 0 ; var acc = arguments [1 ]; if (arguments [1 ]===undefined ){ if (this .arr .length ===0 ) throw new Error ('initval and array.length===0' ); acc = this .arr [i++]; } for (;i<this .arr .length ;i++) acc = callback.call (this , acc, this .arr [i]); return acc; } Array .prototype .filter = function (callback ){ if (Object .prototype .toString .call (callback)!=='[object Function]' ) throw new TypeError ('callback is not a function' ); let res = []; for (let i=0 ;i<this .arr .length ;i++) if (callback.call (arguments [1 ]||window , this .arr [i], i, this .arr )) res.push (this .arr [i]); return res; } Array .prototype .find = function (callback ){ if (Object .prototype .toString .call (callback)!=='[object Function]' ) throw new TypeError ('callback is not a function' ); if (this .arr .length ===0 ) return true ; for (let i=0 ;i<this .arr .length ;i++) if (callback.call (arguments [1 ]||window , this .arr [i], i, this .arr )) return this .arr [i]; return undefined ; } Array .prototype .indexOf = function (findVal, beginIndex=0 ){ if (this .arr .length <1 ||beginIndex>this .arr .length ) return -1 ; if (!findVal) return 0 ; beginIndex=beginIndex<=0 ?0 :beginIndex; for (let i=0 ;i<this .arr .length ;i++) if (this .arr [i]===findVal) return i; return -1 ; } window .Array = Array ; })(window );
数组扁平化 示例:
1 const arr = [1, 2, 3, 4, [1, 2, 3, [1, 2, 3, [1, 2, 3]]], 5, "string", { name: "弹铁蛋同学" }];
代码:
1 2 3 4 5 6 7 8 9 10 function flat (arr, num=1 ){ if (num<0 ) return arr; return num>1 ?arr.reduce ((pre, cur )=> { return pre.concat (Array .isArray (cur)?flat (cur, num-1 ):cur) }, []) :arr.slice () }
数组转树 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 [{id : , pid : }, {id : , pid : }] [{ id : , children : [{ pid : , id : , children : [] },{ pid : , id : , children : [] }] },{ id : , children : [{ pid : , id : , children : [] },{ pid : , id : , children : [] }] }] function arrayToTree (items ){ const result = []; const itemMap = {}; for (const item of items){ const id = item.id ; const pid = item.pid ; if (!itemMap[id]) itemMap[id] = { children : [] } itemMap[id] = { ...item, children : itemMap[id]['children' ] } const treeItem = itemMap[id]; if (pid===0 ) result.push (treeItem); else { if (!itemMap[pid]) itemMap[pid]={ children : [] } itemMap[pid].children .push (treeItem); } } return result; }
树转数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 function treeToList (data ){ let res = []; const dfs = tree=>{ tree.forEach (item => { if (item.children ){ dfs (item.children ); delete item.children ; } res.push (item); }) } dfs (data); return res; }
类数组转化为数组 1 2 3 4 5 [...arr]; Array .from (arr);Array .apply (null , arr);Array .prototype .slice .call (arr);Array .prototype .concat .apply ([], arr);
防抖节流:
非立即执行防抖节流:
防抖 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 function debounce (func, wait, immediate ){ let timeout, result; var debounced = function ( ){ let context = this ; let args = arguments ; if (timeout) clearTimeout (timeout); if (immediate){ let callnow = !timeout; timeout = setTimeout (function ( ){ timeout = null ; }, wait); if (callnow){ result = func.apply (context, args); } }else { timeout = setTimeout (function ( ){ result = func.apply (context, args); timeout = null ; }, wait); } return result; }; debounced.cancel = function ( ){ clearTimeout (timeout); timeout = null ; } return debounced; }
节流 两种解决思路:1.类似debounce的方法2.采用时间戳的差
两种解决方式的差异
第一种先等待够规定时间,再执行
第二种先执行目标函数,再等待规定时间
有option选项,{leading: boolean, trailing: boolean}
leading用于设置第一次是否执行
boolean用于设置最后一次是否执行
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 function throttle (fn, wait, option ){ let timeout; let old = 0 ; if (!option) option = {}; return function ( ){ let context = this ; let args = arguments ; let now = new Date ().getTime (); if (!old&&option.leading ===false ) old = now; let remain = wait - (now - old); if (remain<=0 ||remain>wait){ if (timeout){ clearTimeout (timeout); timeout = null ; } fn.apply (context,args); old = now; }else if (!timeout && option.trailing ){ timeout = setTimeout (()=> { fn.apply (context, args); timeout = null ; old = option.leading ===false ?0 :new Date ().getTime () }, remain); } } }
setTimeout模拟setInterval 1 2 3 4 5 6 7 8 9 10 let timer = null ;function myInterval (func, wait ){ let interv = function ( ){ func (); timer = setTimeout (interv, wait); }; timer = setTimeout (interv, wait); } myInterval (function ( ){}, 20 );
setInterval模拟setTimeout 1 2 3 4 5 6 const mySetTimeout = (fn, time )=>{ interval = setInterval (()=> { fn (); clearInterval (interval); }, time); }
Ajax 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 function ajax ({url=null , method='GET' ,dataType='JSON' ,async =true } ){ return new Promise ((resolve, reject )=> { let xhr = new XMLHttpRequest (); xhr.open (method, url, async ); xhr.responseType = dataType; xhr.onreadystatechange = ()=> { if (!(xhr.status >=200 &&xhr.status <300 )) return ; if (xhr.readyState ===4 ) resolve (xhr.responseText ); } xhr.onerror = err => { reject (err); } xhr.send (); }) }
call 1 2 3 4 5 6 7 8 Function .prototype .call = function (context, ...args ){ let context = context || window ; context.fn = this ; let res = context.fn (...args); delete context.fn ; return res; }
apply 1 2 3 4 5 6 7 8 9 10 11 12 Function .prototype .apply = function (context, args ){ let context = context || window ; context.fn = this ; let res; if (args){ res = context.fn (...args); }else { res = context.fn (); } delete context.fn ; return res; }
bind 1 2 3 4 5 6 7 8 9 10 11 12 13 Function .prototype .bind = function (context, ...args1 ){ let context = context || window ; context.fn = this ; return function (...args2 ){ let res; if (args1) res = context.fn (...args1); else res = context.fn (...args2); delete context.fn ; return res; } }
需要考虑柯里化以及new构造函数的问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 Function .prototype .bind = function ( ){ let context = arguments [0 ]; let outArgs = Array .from (arguments ).slice (1 ); let outThis = this ; if (typeof outThis !== 'function' ) throw new Error ('the caller is not a function' ); const cb = function ( ){ let isNew = typeof new .target !== 'undefined' ; let inArgs = Array .from (arguments ); return outThis.apply (isNew?this :context, outArgs.concat (inArgs)); } cb.prototype = outThis.prototype ; return cb; }
new 1 2 3 4 5 6 function new (constructor, arguments ){ let obj = Object .create (null ); obj.prototype = constructor.prototype ; let res = Object .apply (obj, arguments ); return typeof res === 'object' ?res :obj; }
create 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Object .prototype .create = function (proto, property ){ if (proto===null ||typeof proto!=='function' &&typeof proto!=='object' ) throw TypeError ('prototype should be an object' ); function F ( ){} F.prototype = proto; let obj = new F (); if (property){ Object .keys (property).forEach (key => { let value = property[key]; if (key===null ||typeof key!=='object' ) throw TypeError ('property should be an object' ); else Object .defineProperty (obj, key, value); }) } return obj; }
instanceof 1 2 3 4 5 6 7 8 function instanceof (left, right ){ while (left){ if (left.__proto__ ===right.prototype ) return true ; left = left.__proto__ ; } return false ; }
Object.is 1 2 3 4 5 6 7 8 9 10 Object .is = function (x, y ){ if (x===y) return x!==0 || 1 /x===1 /y; return x!==x&&y!==y; }
deepclone 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 const getType = target=>Object .prototype .toString .call (target);const isObject = target=>target!==null &&(typeof target==='object' ||typeof target==='function' )const canTranverse = { '[object Object]' : true , '[object Map]' : true , '[object Set]' : true , '[object Array]' : true , '[object Argument]' : true } const handleFunc = target=>{ const funcString = target.toString (); if (target.prototype ){ let bodyexp = /(?<={)(.|\n)+(?=})/ ; let paramexp = /(?<=\().+(?=\))\s+{/ ; let body = bodyexp.exec (funcString)[0 ]; let param = paramexp.exec (funcString)[0 ]; if (param){ return new Function (...param, body); }else return new Function (body); }else { return eval (funcString); } } const handleExp = target=>{ const {source, flags} = target; let res = new RegExp (source, flag); res.lastIndex = target.lastIndex ; return res; } const handle = (target, type )=>{ switch (type){ case '[object Function]' : return handleFunc (target); case '[object RegExp]' : return hanldeExp (target); case '[object Error]' : case '[object Date]' : return new target.constructor (target ); case '[object Boolean]' : return new Object (Boolean .prototype .valueOf .call (target)); case '[object Number]' : return new Object (Number .prototype .valueOf .call (target)); case '[object String]' : return new Object (String .prototype .valueOf .call (target)); case '[object Symbol]' : return new Object (Symbol .prototype .valueOf .call (target)); default : return new target.constructor (target ); } } function deepClone (target, weakmap=new WeakMap () ){ let type = getType (target); if (!isObject (type)) return target; let cloneTarget; if (!canTranverse[type]) handle (target, type); else cloneTarget = new target.constructor ( ); if (weakmap.get (target)) return target; else weakmap.set (target, true ); if (type==='[object Array]' ){ for (let index in target) cloneTarget[index] = deepClone (target[index],weakmap); } if (type==='[object Map]' ){ Object .keys (target).forEach (key => { cloneTarget.set (deepClone (key, weakmap), deepClone (target[key], weakmap)); }) } if (type==='[object Set]' ){ target.forEach ((item, key )=> { cloneTarget.add (key, deepClone (item, weakmap)); }) } return cloneTarget; }
继承 原型链继承 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 function Father ( ){ this .property = true ; } Father .prototype .getFatherValue = function ( ){ return this .property ; } function Son ( ){ this .subproperty = false ; } Son .prototype = new Father ();Son .prototype .getSonValue = function ( ){ return this .subproperty ; } var instance = new Son ();instance.getFatherValue ();
构造函数式继承 1 2 3 4 5 6 7 8 9 10 11 12 13 function Father ( ){ this .colors = ['red' , 'green' ]; } function Son ( ){ Father .call (this ); } var instance = new Son ();instance.colors .push ('purple' );
组合式继承 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 function Father (name ){ this .name = name; this .colors = ['red' ]; } Father .prototype .sayName = function ( ){ alert (this .name ); } function Son (name, age ){ Father .call (this , name); this .age = age; } Son .prototype = new Father ();Son .prototype .constructor = Son ;Son .prototype .sayAge = function ( ){ alert (this .age ); } var instance = new Son ('aaa' , 12 );instance.colors .push ('purple' );
原型式继承,浅拷贝 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 function object (o ){ function F ( ){} F.prototype = o; return new F (); } var person = { name : 'hh' , colors : ['red' ] } var anotherPerson = Object .create (person, { name : { value : 'tom' } })
寄生式继承 1 2 3 4 5 6 7 8 9 function createPerson (original ){ var clone = Object .create (original); clone.sayGood = function ( ){ alert ('hello world' ); } return clone; }
寄生组合式继承 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function Father (name ){ this .name = name; this .colors = ['red' ]; } Father .prototype .sayName = function ( ){ alert (this .name ); } function Son (name, age ){ Father .call (this , name); this .age = age; } var anotherPrototype = Object .create (Father .prototype );anotherPrototype.constructor = Son ; Son .prototype = anotherPrototype;Son .prototype .sayAge = function ( ){ alert (this .age ); } var instance = new Son ('lu' , 22 );
大数相加 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function add (a, b ){ let maxlength = Math .max (a.length , b.length ); a = a.padStart (maxlength, 0 ); b = b.padStart (maxlength, 0 ); let t = 0 ; let f = 0 ; let sum = "" ; for (let i=maxlength-1 ;i>=0 ;i--){ t = parseInt (a[i])+parseInt (b[i])+f; f = Math .floor (t/10 ); sum = t%10 +sum; } if (f!=0 ) sum='' +f+sum; return sum; }
表单校验 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 const strategies = { isNoEmpty : function (value, errorMsg ){ if (value === '' ) return errorMsg; }, minLength : function (value, length, errorMsg ){ if (value.length <length) return errorMsg; }, isMobile : function (value, errorMsg ){ if (!/^$/ .test (value)) return errorMsg; } }; class Validator { constructor ( ){ this .cache = []; } add (dom, rules ){ for (let i=0 ,rule;rule=rules[i++];){ let strategyAry = rule.strategy .split (':' ); let errorMsg = rule.errorMsg ; this .cache .push (()=> { let strategy = strategyAry.shift (); strategyAry.unshift (dom.value ); strategyAry.push (errorMsg); return strategies[strategy].apply (dom, strategyAry); }) } } start ( ){ for (let i=0 ,validatorFunc;validatorFunc=this .cache [i++];){ let errorMsg = validatorFunc (); if (errorMsg) return errorMsg; } } } let registerForm = document .getElementById ('registerForm' );let validateFunc = function ( ){ let validator = new Validator (); validator.add (registerForm.username , [{ strategy : 'isNoEmpty' , errorMsg : 'cannot input empty' },{ strategy : 'minLength:2' , errorMsg : 'input is too short' }]) validator.add (registerForm.mobile , [{ strategy : 'isMobile' , errorMsg : 'mobile is invalid' }]) return validator.start (); } registerForm.onsubmit = function ( ){ let errorMsg = validateFunc (); if (errorMsg) alert (errorMsg); }
发布订阅者模式 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 class EventEmitter { constructor ( ){ this .events = {}; } on (type, callback ){ if (!this .events [type]) this .events [type] = [callback]; else this .events [type].push (callback); } off (type, callback ){ if (!this .events [type]) return ; this .events [type] = this .events [type].filter (item => { return item!=callback; }) } once (type, callback ){ function fn ( ){ callback (); this .off (type, fn); } this .on (type, fn); } emit (type, ...rest ){ this .events [type]&&this .events [type].forEach (fn => fn.apply (this , rest)); } } const event = new EventEmitter ();const handle = (...rest )=>{ console .log (rest); } event.on ('click' , handle); event.emit ('click' , 1 , 2 , 3 , 4 ); event.off ('click' , handle);
小数据:分片渲染大数据量数据 requestAnimationFrame版 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 let ul = document .getElementById ('container' );let total = 100000 ;let once = 20 ;let index = 0 ;function loop (curTotal, curIndex ){ if (curTotal<=0 ) return ; let pageCount = Math .min (curTotal, once); window .requestAnimationFrame (function ( ){ for (let i=0 ;i<pageCount;i++){ let li = document .createElement ('li' ); li.innerText = curIndex+i+":" +~~(Math .random ()*total); ul.appendChild (li); } }) loop (curTotal-pageCount, curIndex+pageCount); } loop (total, index);
DocumentFragment版 DocumentFragment,文档片段接口,表示一个没有父级文件的最小文档对象。它被作为一个轻量版的Document
使用,用于存储已排好版的或尚未打理好格式的XML片段。最大的区别是因为DocumentFragment
不是真实DOM树的一部分,它的变化不会触发DOM树的(重新渲染) ,且不会导致性能等问题。 可以使用document.createDocumentFragment
方法或者构造函数来创建一个空的DocumentFragment。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 let ul = document .getElementById ('container' );let total = 100000 ;let once = 20 ;let index = 0 ;function loop (curTotal, curIndex ){ if (curTotal<=0 ) return ; let pageCount = Math .min (curTotal, once); window .requestAnimationFrame (function ( ){ let fragment = document .createDocumentFragment (); for (let i=0 ;i<pageCount;i++){ let li = document .createElement ('li' ); li.innerText = curIndex+i+":" +~~(Math .random ()*total); fragment.appendChild (li); } ul.appendChild (fragment); }) loop (curTotal-pageCount, curIndex+pageCount); } loop (total, index);
模板字符串解析 1 2 3 4 5 6 7 8 9 10 11 12 13 14 function render (template, data ){ let computed = template.replace (/\{\{(\w+)\}\}/g , function (match, key ){ return data[key]; }) return computed; }
LRUcache 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 class LRUcache { constructor (capacity ){ this .secretKey = new Map (); this .capacity = capacity; } get (key ){ if (this .secretKey .has (key)){ let tempValue = this .secretKey .get (key); this .secretKey .delete (key); this .secretKey .set (key, tempValue); return tempValue; }else return -1 ; } put (key, value ){ if (this .secretKey .has (key)){ this .secretKey .delete (key); this .secretKey .set (key, value); }else if (this .secretKey .size <this .capacity ) this .secretKey .set (key, value); else { this .secretKey .set (key, value); this .secretKey .delete (this .secretKey .keys ().next ().value ); } } }
LazyMan 场景
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 实现一个LazyMan,可以按照以下方式调用: LazyMan(“Hank”)输出: Hi! This is Hank! LazyMan(“Hank”).sleep(10).eat(“dinner”)输出 Hi! This is Hank! //等待10秒.. Wake up after 10 Eat dinner~ LazyMan(“Hank”).eat(“dinner”).eat(“supper”)输出 Hi This is Hank! Eat dinner~ Eat supper~ LazyMan(“Hank”).eat(“supper”).sleepFirst(5)输出 //等待5秒 Wake up after 5 Hi This is Hank! Eat supper
代码
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 class _LazyMan { constructor (name ){ this .tasks = []; const task = ( )=>{ console .log (`hi! this is ${name} ` ); this .next (); }; this .tasks .push (task); setTimeout (()=> { this .next (); }, 0 ); } next ( ){ const task = this .tasks .shift (); task && task (); } sleep (time ){ this ._sleepWrapper (time, false ); return this ; } sleepFirst (time ){ this ._sleepWrapper (time, false ); return this ; } _sleepWrapper (time, first ){ const task = ( )=>{ setTimeout (()=> { console .log (`wake up after ${time} ` ); this .next (); }, time*1000 ); } if (first) this .tasks .unshift (task); else this .tasks .push (task); } eat (name ){ const task = ( )=>{ console .log (`Eat ${name} ` ); this .next (); }; this .tasks .push (task); return this ; } } function LazyMan (name ){ return new _LazyMan (name); }
compose 场景
1 2 3 4 5 compose 是函数式编程中很重要的函数之一。 compose 函数的作用就是组合函数的,将函数串联起来执行,将多个函数组合起来, 一个函数的输出结果是另一个函数的输入参数,一旦第一个函数开始执行, 就会像多米诺骨牌一样推导执行了。 compose(f,g,m,n)(x) === f(g(m(n(x))))
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 function compose1 ( ){ var fns = [].slice .call (arguments ); return function (initArg ){ var res = initArg; for (var i=fns.length -1 ;i>=0 ;i--) res = fns[i](res); return res; } } function compose2 (...funcs ){ if (funcs.length ===0 ) return v => v; if (funcs.length ===1 ) return funcs[0 ]; return funcs.reduce ((a, b )=> { return function (...args ){ return a (b (...args)); } }) }
curry 场景
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 所谓”柯里化”,简单来说就是把一个多参数的函数,转化为单参数函数 // 普通的add函数 function add(x, y) { return x + y } // Currying后 function curryingAdd(x) { return function (y) { return x + y } } add(1, 2) // 3 curryingAdd(1)(2) // 3
代码
1 2 3 4 5 6 7 8 9 10 11 12 function currying (fn, ...args ){ const length = fn.length ; let allargs = [...args]; const res = (...newArgs )=>{ allargs = [...allargs, ...newArgs]; if (allargs.length === length) return fn (...allargs); else return res; } return res; }
add 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function add (...args ){ let allargs = [...args]; function fn (...args2 ){ allargs = [...allargs, ...args2]; return fn; } fn.toString = function ( ){ if (!allargs.length ) return ; return allargs.reduce ((sum, cur )=> { return sum+cur; }) } return fn; }
通用事件侦听器函数 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 const EventUtils = { addEvent : function (element, type, handler ){ if (element.addEventListener ) element.addEventListener (type, handler, false ); else if (element.attachEvent ) element.attachEvent ("on" +type, handler); else element["on" +type]=handler; }, removeEvent : function (element, type, handler ){ if (element.removeEventListener ) element.removeEventListener (type, handler, false ); else if (element.detachEvent ) element.detachEvent ('on' +type, handler); else element['on' +type]=null ; }, stopPropagation : function (ev ){ if (ev.stopPropagation ) ev.stopPropagation (); else ev.cancelBubble = true ; }, preventDefault : function (ev ){ if (ev.preventDefault ) ev.preventDefault (); else ev.returnValue = false ; }, getTarget : function (ev ){ return ev.target || ev.srcElement ; } }
dom2json 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 function dom2json (dom ){ let obj = {}; obj.tag = dom.tagName ; obj.children = []; dom.childNodes .forEach (child => { obj.children .push (dom2json (child)); }) }
json2dom 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 function json2dom (vdom ){ if (typeof vdom === 'number' ) vdom = String (vdom); if (typeof vdom === 'string' ) return document .createTextNode (vdom); const dom = document .createElement (vdom.tag ); if (vdom.attrs ){ Object .keys (vdom.attrs ).forEach (key => { const value = vdom.attrs [key]; dom.setAttribute (key, value); }) } vdom.children .forEach (child => { dom.appendChild (json2dom (child)); }) return dom; }
async/await 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 function run (gen ){ return new Promise ((resolve, reject )=> { let g = gen (); function next (value ){ let res; try { res = g.next (value); }catch (err){ return reject (err); } if (res.done ) return resolve (res.value ); Promise .resolve (res.value ).then ( value => next (value), reason => g.throw (reason) ) } }) }
数组乱序 1 2 3 4 5 6 7 function shuffle (arr ){ let i = arr.length ; while (i){ let j=Math .floor (Math .random ()*i--); [arr[j], arr[i]]=[arr[i], arr[j]]; } }
并行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 class Schedule { constructor (limit ) { this .maxCount = limit; this .queue = []; this .runCount = 0 ; } add (time, order ) { const createPromise = ( ) => { return new Promise ((resolve, reject ) => { setTimeout (() => { resolve (order); }, time); }) }; this .queue .push (createPromise); } taskStart ( ) { for (let i = 0 ; i < this .queue .length ; i++) { this .request (); } } request ( ) { if (this .runCount >= this .maxCount || !this .queue || !this .queue .length ) { return ; } this .runCount ++; this .queue .shift ()().then (() => { this .runCount --; this .request (); }) } }
双向数据绑定 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 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title></title> </head> <body> <div> show: <h1></h1> input: <input type="text"> </div> <script> function defined(){ let obj = {}; let val; Object.defineProperties(obj, { val: { get(){ return val; }, set(newVal){ val = newVal; document.querySelector('h1').innerText = val; } } }); return obj; } let newObj = defined(); document.querySelector('input').addEventListener('input', function(){ newObj.val = document.querySelector('input').value; }) </script> </body> </html>
tips 数组
reduce \ forEach \ filter \ every \ some会跳过空位
map \ slice 不会跳过空位