本篇持续收集日常遇到的问题的解决方案和一些代码片段
问题 1、git clone换行符问题 在 git clone
过程,git将所有文件换行符(LF)更换成本地换行符(CRLF)了,而 eslint
检查工具要求换行符为 LF
解决方法 在任意位置的命令行窗口中输入以下命令:
1 2 git config --global core.autocrlf false git config --global core.eol lf
将 git 的 autocrlf
功能设置为 false
,并把 eol
(end of line)设置为lf
,再重新clone一下代码就可以啦
2、ES6对象简写 之前写对象里的方法一直使用的是getName:()=>{...}
的形式,后来感觉不好看,想要改成getName(){...}
的形式,但是手动修改是不可能的,可以使用正则进行全局替换。
1 2 3 4 # 匹配字符 (\w+)\: ?(async )? \((.*)\) \=\> # 替换为 $2 $1 \($3 \)
代码 防抖与节流 1 2 <button id ="debounceBtn" > 防抖Click</button > <button id ="throttleBtn" > 节流Click</button >
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 debounceBtn.onclick = debounce (() => { console .log ("防抖" ) }, 3000 ) throttleBtn.onclick = throttle (() => { console .log ("节流" ) }, 3000 ) function debounce (fn, wait = 2000 ) { let timer = null return function (...args ) { if (timer) { clearTimeout (timer) } timer = setTimeout (() => { fn.apply (this , args) }, wait) } } function throttle (fn, delay = 2000 ) { let prevTime = 0 return function (...args ) { const nowTime = Date .now () if (nowTime - prevTime > delay) { prevTime = nowTime fn.apply (this , args) } } }
判断类型 1 2 3 function myTypeOf (data ) { return Object .prototype .toString .call (data).slice (8 , -1 ) }
统计字符串中每个字符出现的次数 1 2 3 4 function charCount (str ) { const count = [...str].reduce ((p, v ) => (p[v]++ || (p[v] = 1 ), p), {}) return Object .fromEntries (Object .entries (count).sort ((a, b ) => b[1 ] - a[1 ])) }
对象数组去重 1 2 3 4 function uniqueObjInArray (arr, keyStr ) { const map = new Map (); return arr.filter (v => !map.has (v[keyStr]) && map.set (v[keyStr], 1 )); }
深拷贝 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 function deepClone (value ) { const cache = new WeakMap () function _clone (val ) { if (val === null || typeof val !== 'object' ) return val if (cache.get (val)) return cache.get (val) const result = Array .isArray (val) ? [] : {} cache.set (val, result) for (const key in val) { if (val.hasOwnProperty (key)) { result[key] = _clone (val[key]) } } return result } return _clone (value) }
EventBus 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 class EventBus { constructor ( ) { this .events = new Map () } on (name, callback ) { if (!this .events .has (name)) { this .events .set (name, []) } this .events .get (name).push (callback) } emit (name, ...args ) { if (this .events .has (name)) { this .events .get (name).forEach (cb => cb (...args)) } } off (name, callback ) { if (this .events .has (name)) { if (callback) this .events .set (name, this .events .get (name).filter (e => e !== callback)) else this .events .delete (name) } } once (name, callback ) { let once = (...args ) => { callback (...args) this .off (name, once) } this .on (name, once) } } const bus = new EventBus ()function handleEvt1 ( ) { console .log ("evt1 triggered" ) } function handleEvt2 (data ) { console .log ("evt2 triggered" , data) } function handleEvt3 (data ) { console .log ("evt3 triggered" , data) } bus.on ("evt1" , handleEvt1) bus.on ("evt2" , handleEvt2) bus.once ("evt3" , handleEvt3) bus.emit ("evt1" ) bus.off ("evt1" , handleEvt1) bus.emit ("evt1" ) bus.emit ("evt2" , "ohmygod" ) bus.emit ("evt3" , "执行一次" ) bus.emit ("evt3" , "再执行一次" )
获取嵌套对象中指定路径的值 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function getValue (obj, path ) { const paths = Array .isArray (path) ? path : path.split ('.' ) return paths.reduce ((current, key ) => { return current && current[key] !== undefined ? current[key] : undefined ; }, obj); } const obj = { a : { b : { c : 113 , d : null } } } console .log (getValue (obj, "a.b.c" )) console .log (getValue (obj, ['a' , 'b' ]))
手写call 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 Function .prototype .myCall = function (ctx, ...args ) { ctx = ctx === null || ctx === undefined ? globalThis : Object (ctx) const key = Symbol ('fn' ) Object .defineProperty (ctx, key, { enumerable : false , value : this }) const result = ctx[key](...args) delete ctx[key] return result } const obj = { test (a, b ) { console .log (this ) return a + b } } obj.test .myCall (obj, 1 , 2 )
数组转树形结构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 function arrayToTree<T extends object , K extends keyof T, P extends keyof T>(arr : T[], key : K, parentKey : P) { type Res = T & { children?: Res [] } const MAP = new Map <T[K] | T[P], Res >() const result : Res [] = [] for (const item of arr) { const id = item[key] const parentId = item[parentKey] const parent = MAP .get (parentId) if (parent) { if (!parent.children ) parent.children = [] parent.children .push (item) } else { result.push (item) } MAP .set (id, item) } return result }
排序算法 冒泡排序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 function bubbleSort (arr ) { for (let i = 0 ; i < arr.length - 1 ; i++) { let flag = true for (let j = 0 ; j < arr.length - 1 - i; j++) { if (arr[j] > arr[j + 1 ]) { flag = false swap (arr, j, j + 1 ) } } if (flag) break } return arr } function swap (arr, a, b ) { const tmp = arr[a] arr[a] = arr[b] arr[b] = tmp }
选择排序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 function selectionSort (arr ) { let min for (let i = 0 ; i < arr.length - 1 ; i++) { min = i for (let j = i; j < arr.length ; j++) { if (arr[min] > arr[j]) { min = j } } if (i !== min) { swap (arr, i, min) } } return arr } function swap (arr, a, b ) { const tmp = arr[a] arr[a] = arr[b] arr[b] = tmp }
插入排序 1 2 3 4 5 6 7 8 9 10 11 12 13 function insertionSort (arr ) { let tmp for (let i = 1 ; i < arr.length ; i++) { tmp = arr[i] let j = i while (j > 0 && arr[j - 1 ] > tmp) { arr[j] = arr[j - 1 ] j-- } arr[j] = tmp } return arr }
归并排序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 function mergeSort (arr ) { if (arr.length > 1 ) { const mid = Math .floor (arr.length / 2 ) const left = mergeSort (arr.slice (0 , mid)) const right = mergeSort (arr.slice (mid, arr.length )) arr = merge (left, right) } return arr } function merge (left, right ) { let i = 0 let j = 0 const result = [] while (i < left.length && j < right.length ) { result.push (left[i] < right[j] ? left[i++] : right[j++]) } return result.concat (i < left.length ? left.slice (i) : right.slice (j)) }
快速排序 1 2 3 4 5 6 7 8 function quickSort (arr ) { if (arr.length < 2 ) return arr let base = arr[0 ] const minArr = arr.slice (1 ).filter (v => v <= base) const maxArr = arr.slice (1 ).filter (v => v > base) return [...quickSort (minArr), base, ...quickSort (maxArr)] }
计数排序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 function countingSort (arr ) { if (arr.length < 2 ) return arr const max = Math .max (...arr) const counts = new Array (max + 1 ) arr.forEach (item => { if (!counts[item]) { counts[item] = 0 } counts[item]++ }) let sortIndex = 0 const newArr = [] counts.forEach ((item, index ) => { while (item > 0 ) { newArr[sortIndex++] = index item-- } }) return newArr }
桶排序 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 function bucketSort (arr, bucketSize = 3 ) { if (arr.length < 2 ) return arr const buckets = createBucket (arr, bucketSize) return sortBuckets (buckets) } function createBucket (arr, bucketSize ) { const min = Math .min (...arr) const max = Math .max (...arr) const bucketCount = Math .floor ((max - min) / bucketSize) + 1 const buckets = [...new Array (bucketCount)].map (() => []) for (let i = 0 ; i < arr.length ; i++) { const index = Math .floor ((arr[i] - min) / bucketSize) buckets[index].push (arr[i]) } return buckets } function sortBuckets (arr ) { const sorted = [] for (let i = 0 ; i < arr.length ; i++) { if (arr[i]) { insertionSort (arr[i]) sorted.push (...arr[i]) } } return sorted } function insertionSort (arr ) { let tmp for (let i = 1 ; i < arr.length ; i++) { tmp = arr[i] let j = i while (j > 0 && arr[j - 1 ] > tmp) { arr[j] = arr[j - 1 ] j-- } arr[j] = tmp } }
基数排序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function radixSort (arr ) { const base = 10 let divider = 1 const max = Math .max (...arr) while (divider <= max) { const buckets = [...new Array (base)].map (() => []) for (let val of arr) { buckets[Math .floor (val / divider) % base].push (val) } arr = [].concat (...buckets) divider *= base } return arr }
搜索算法 顺序搜索 1 2 3 4 5 6 7 function sequentialSearch (arr, target ) { for (let i = 0 ; i < arr.length ; i++) { if (arr[i] === target) { return i } } }
二分搜索 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function binarySearch (arr, target, start, end ) { start = start || 0 end = end || arr.length - 1 if (start <= end && target >= arr[start] && target <= arr[end]) { if (arr[start] === target) return start if (arr[end] === target) return end let mid = Math .ceil ((start + end) / 2 ) if (arr[mid] === target) return mid if (arr[mid] > target) return binarySearch (arr, target, start, mid - 1 ) return binarySearch (arr, target, mid + 1 , end) } return -1 }
内插搜索 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function insertionSearch (arr, target, start, end ) { start = start || 0 end = end || arr.length - 1 if (start <= end && target >= arr[start] && target <= arr[end]) { if (arr[start] === target) return start if (arr[end] === target) return end let mid = start + Math .floor ((target - arr[start]) / (arr[end] - arr[start]) * (end - start)) if (arr[mid] === target) return mid if (arr[mid] > target) return insertionSearch (arr, target, start, mid - 1 ) return insertionSearch (arr, target, mid + 1 , end) } return -1 }
随机算法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 function shuffle (arr ) { for (let i = arr.length - 1 ; i > 0 ; i--) { const randIndex = Math .floor (Math .random () * (i + 1 )) swap (arr, i, randIndex) } return arr } function swap (arr, a, b ) { const tmp = arr[a] arr[a] = arr[b] arr[b] = tmp }