nutils-js
是我封裝的一個模塊化、高性能的 JavaScript 實用工具庫。前端
前端開發中常常會遇到Array
、Object
、String
、Number
等數據處理,或者是防抖節流函數等性能優化亦或是 URL 參數處理、類型判斷等等操做,爲了提升開發效率,我將這些常見公共方法進行抽離並封裝好,發佈在 npm 上,後續若有更優的寫法也會作進一步的更新。另外讀者朋友們若是有好的建議或者想爲本項目貢獻一份力的話,歡迎爲本項目提交 pr,一塊兒探討和交流。git
$ npm i --save nutils-js
const nutils = require('nutils-js') nutils.multArray([1, 2, 3], 2)
multArray
二維數組轉換flatten
扁平化數組flattenDeep
指定層級扁平化數組isArrayEqual
檢查兩個數組各項相等allEqual
檢查數組各項相等diffArray
具備惟一array
值的數組haveArr
具備共同array
值的數組uniqueArray
數組去重uniqueArrayObject
數組對象去重treeData
生成樹結構數據ascArr
數組升序descArr
數組降序shuffle
隨機排序takeArray
截取數組開始指定的元素takeLastArray
截取數組最後指定的元素cloneArray
克隆數組maxArray
數組中最大值validArray
去除數組中的無效值randomNumber
指定範圍的隨機整數average
求平均值averageBy
檢查數組對象各項相等aboutEqual
兩個值是否約等於getLineSize
計算兩點之間的距離sum
數組中值總和後續的更新,請點擊
GitHub
倉庫進行查看github若是對本文有啥疑問或建議,歡迎加我微信
qqlcx55
一塊兒學習哈web
Github地址算法
multArray
二維數組轉換將數組(array)拆分紅多個子數組,並將這些子數組組成一個新數組。npm
multArray(array, count)
參數數組
array
須要處理的數組count = 8
子數組須要的長度示例瀏覽器
multArray([1, 2, 3, 4, 5, 6, 7], 2) => [[1, 2], [3, 4], [5, 6], [7]] multArray(['a', 'b', 'c', 'd'], 3) => [['a', 'b', 'c'], ['d']]
源碼性能優化
function multArray(arr, count = 8) { let pages = [] arr.forEach((item, index) => { const page = Math.floor(index / count) if (!pages[page]) pages[page] = [] pages[page].push(item) }) return pages }
flatten
扁平化數組將多層嵌套數組(array)拆分紅一個數組bash
flatten(array)
參數
array
多層嵌套數組示例
flatten([1, [2], [3], [4, 5]]) // [1, 2, 3, 4, 5]
源碼
// 扁平化 Map 方法 const flatten = arr => [].concat(...arr.map(v => (Array.isArray(v) ? flatten(v) : v))) // 扁平化 reduce 方法 const flatten = arr => arr.reduce((a, c) => a.concat(Array.isArray(c) ? flatten(c) : c), [])
flattenDeep
指定層級扁平化數組將多層嵌套數組(array)拆分紅指定層級數組
flattenDeep(array, depth)
參數
array
多層嵌套數組 depth =
減小的嵌套層級數示例
flattenDeep([1, [2, [3, [4]], 5]], 1) // => [1, 2, [3, [4]], 5] // ES6方法 `flat(depth)` ;[1, [2, [3, [4]], 5]].flat(1) // => [1, 2, [3, [4]], 5]
源碼
const flattenDeep = (arr, depth = 1) => arr.reduce((a, v) => a.concat(depth > 1 && Array.isArray(v) ? flatten(v, depth - 1) : v), [])
isArrayEqual
檢查兩個數組各項相等比較兩個數組內的各項值是否相等,返回一個Boolean
值
isArrayEqual(array, array)
參數
array
要檢查的數組array
要檢查的數組示例
isArrayEqual([6, 5, 2, 4, 1, 3], [1, 2, 3, 4, 5, 6]) // => true isArrayEqual([6, 5, 2, 7, 1, 3], [1, 2, 3, 4, 5, 6]) // => false
源碼
const isArrayEqual = (a, b, has = true) => { if (a.length !== b.length) return (has = false) const s = new Set(b) if (a.find(x => !s.has(x))) return (has = false) return has }
allEqual
檢查數組各項相等allEqual(array)
參數
array
要檢查的數組示例
allEqual([1, 2, 3, 4, 5, 6]) // => false allEqual([1, 1, 1, 1]) // => true
源碼
const allEqual = arr => arr.every(val => val === arr[0])
diffArray
具備惟一array
值的數組建立一個具備惟一 array 值的數組,每一個值不包含在其餘給定的數組中
diffArray(array, array2)
參數
array
要檢查的數組array2
要排除的數組示例
diffArray([1, 2, 6, 7], [1, 2, 9, 5]) // => [ 6, 7 ]
源碼
const diffArray = (a, b) => { const s = new Set(b) let arr = a.filter(x => !s.has(x)) return arr }
haveArr
具備共同array
值的數組建立一個具備共同 array 值的數組,每一個值包含在其餘給定的數組中
haveArr(array, array2)
參數
array
要檢查的數組array2
要包含的數組示例
haveArr([1, 2, 6, 7], [1, 2, 9, 5]) // => [ 1, 2 ]
源碼
const haveArr = (a, b) => { const s = new Set(b) return a.filter(x => s.has(x)) } // ES6 includes const haveArr = (arr, values) => arr.filter(v => values.includes(v))
uniqueArray
數組去重建立一個去重後的 array 數組副本
uniqueArray(array)
參數
array
要去重的數組示例
uniqueArray([1, 2, 2, 3, 4, 4, 5]) // => [ 1, 2, 3, 4, 5 ]
源碼
const uniqueArray = (...arr) => [...new Set(arr)] const uniqueArray = (...arr) => Array.from(new Set(arr))
uniqueArrayObject
數組對象去重建立一個去重後的 array 數組對象副本
uniqueArrayObject(array)
參數
array
要去重的數組key
要去重的對象屬性值示例
const responseList = [ { id: 1, a: 1 }, { id: 2, a: 2 }, { id: 3, a: 3 }, { id: 1, a: 4 }, { id: 2, a: 2 }, { id: 3, a: 3 }, { id: 1, a: 4 }, { id: 2, a: 2 }, { id: 3, a: 3 }, { id: 1, a: 4 }, { id: 2, a: 2 }, { id: 3, a: 3 }, { id: 1, a: 4 }, ] uniqueArrayObject(responseList, 'id') // => [ { id: 1, a: 1 }, { id: 2, a: 2 }, { id: 3, a: 3 } ]
源碼
const uniqueArrayObject = (arr, key) => { return arr.reduce((acc, cur) => { const ids = acc.map(item => item[key]) return ids.includes(cur[key]) ? acc : [...acc, cur] }, []) }
treeData
生成樹結構數據該函數傳入一個數組, 每項id
對應其父級數據parent_id
,返回一個樹結構數組
treeData(array, id, parent_id)
參數
array
要生成樹結構的數組id
自定義屬性名parent_id
父級自定義屬性名示例
const comments = [ { id: 1, parent_id: null }, { id: 2, parent_id: 1 }, { id: 3, parent_id: 1 }, { id: 4, parent_id: 2 }, { id: 5, parent_id: 4 }, ] treeData(comments) // => [ { id: 1, parent_id: null, children: [ [Object], [Object] ] } ]
源碼
const treeData = (arr, id = null, link = 'parent_id') => arr.filter(item => item[link] === id).map(item => ({ ...item, children: treeData(arr, item.id) }))
ascArr
數組升序返回升序後的新數組
sort()方法會改變原數組,默認按 unicode 碼順序排列
ascArr(array)
參數
array
要檢查的排序數組示例
ascArr([3, 2, 3, 4, 1]) // => [ 1, 2, 3, 3, 4 ]
源碼
// 經過ES6 ...展開運算符淺拷貝一份新數組 const ascArr = arr => [...arr].sort((a, b) => a - b)
descArr
數組降序返回降序後的新數組
descArr(array)
參數
array
要檢查的排序數組示例
descArr([3, 2, 3, 4, 1]) // => [ 1, 2, 3, 3, 4 ]
源碼
const descArr = arr => [...arr].sort((a, b) => b - a)
shuffle
隨機排序建立一個隨機的數組,使用Fisher-Yates
算法隨機排序數組的元素
shuffle(array)
參數
array
要隨機的數組示例
shuffle([2, 3, 1]) // => [3, 1, 2]
源碼
const shuffle = ([...arr]) => { let m = arr.length while (m) { const i = Math.floor(Math.random() * m--) ;[arr[m], arr[i]] = [arr[i], arr[m]] } return arr }
takeArray
截取數組開始指定的元素從 array 數組的最開始一個元素開始提取 n 個元素
takeArray(array, n)
參數
array
要檢索的數組。n=
要提取的元素n
個數。示例
takeArray([2, 3, 1], 2) // => [2, 3]
源碼
const takeArray = (arr, n = 1) => arr.slice(0, n)
takeLastArray
截取數組最後指定的元素從 array 數組的最後一個元素開始提取 n 個元素
takeLastArray(array, n)
參數
array
要檢索的數組。n=
要提取的元素n
個數。示例
takeArray([2, 3, 1], 2) // => [3, 1]
源碼
const takeLastArray = (arr, n = 1) => arr.slice(0, -n)
cloneArray
克隆數組淺拷貝一份數組副本
cloneArray(array)
參數
array
要複製的數組示例
cloneArray([1, 24]) // => [1, 24]
源碼
// ES6 ... const cloneArray = arr => [...arr] // ES6 Array.from const cloneArray = arr => Array.from(arr) // concat() const cloneArray = arr => [].concat(arr) // map() const cloneArray = arr => arr.map(x => x) cloneArray([1, 24]) // [1, 24]
maxArray
數組中最大值過濾原數組中全部的非假值元素,返回數組中的最大值
maxArray(array)
參數
array
待處理的數組示例
maxArray([0, -1, -2, -3, false]) // => 0
源碼
const maxArray = arr => Math.max(...arr.filter(v => Boolean(v) || v === 0))
minArray
數組中最小值過濾原數組中全部的非假值元素,返回數組中的最小值
minArray(array)
參數
array
待處理的數組示例
minArray([0, -1, -2, -3, false]) // => -3
源碼
const minArray = arr => Math.min(...arr.filter(v => Boolean(v) || v === 0))
validArray
去除數組中的無效值建立一個新數組,包含原數組中全部的非假值元素。例如false
, null
,0
, ""
, undefined
, 和 NaN
都是被認爲是「假值」。
validArray(array)
參數
array
待處理的數組示例
minArray([0, 1, false, 2, '', 3]) // => [1, 2, 3]
源碼
const validArray = arr => arr.filter(Boolean)
isObjectEqual
檢查兩個對象各項值相等isObjectEqual(object, object2)
參數
object
待檢索的對象object2
待檢索的對象示例
isObjectEqual({ a: 2, b: 4 }, { b: 4, a: 2 }) // => true isObjectEqual({ a: 2, b: 4, c: 6 }, { b: 4, a: 2 }) // => false
源碼
function isObjectEqual(obj1, obj2, has = true) { // 判斷類型 const o1 = obj1 instanceof Object const o2 = obj2 instanceof Object if (!o1 || !o2) return obj1 === obj2 // 判斷長度 const keys1 = Object.getOwnPropertyNames(obj1) const keys2 = Object.getOwnPropertyNames(obj2) if (keys1.length !== keys2.length) return false // 各項對比 for (let o in obj1) { let t1 = obj1[o] instanceof Object let t2 = obj2[o] instanceof Object if (t1 && t2) { has = diffByObj(obj1[o], obj2[o]) } else if (obj1[o] !== obj2[o]) { has = false break } } return has }
cloneObject
克隆對象淺拷貝一份對象副本
cloneObject(object)
參數
object
要複製的對象示例
const a = { x: 1, y: 1 } const b = cloneObject(a) // => a !== b
源碼
// ES6 ... const cloneObject = (obj, temp = {}) => (temp = { ...obj }) // Object.assign() const cloneObject = obj => Object.assign({}, obj)
debounce
函數防抖在事件被觸發 n 秒後再執行回調,若是在這 n 秒內又被觸發,則從新計時。
debounce(fn, wait)
參數
fn
要防抖動的函數wait=500
須要延遲的毫秒數示例
debounce(()=> { console.log('debounce') }, 1000) // => 1秒後打印'debounce'
源碼
/** * * 防抖 * @parmas fn 回調函數 * @parmas time 規定時間 */ const debounce = (function () { let timer = {} return function (func, wait = 500) { let context = this // 注意 this 指向 let args = arguments // arguments中存着e let name = arguments[0].name || 'arrow' //箭頭函數 if (timer[name]) clearTimeout(timer[name]) timer[name] = setTimeout(() => { func.apply(this, args) }, wait) } })()
throttle
函數節流規定一個單位時間,在這個單位時間內,只能有一次觸發事件的回調函數執行,若是在同一個單位時間內某事件被觸發屢次,只有一次能生效。
throttle(fn, wait)
參數
fn
要節流的函數wait=500
須要延遲的毫秒數示例
throttle(() => { console.log('throttle') }, 1000) // 1秒屢次觸發打印一次`throttle`
源碼
/** * * 節流(規定的時間才觸發) * @parmas fn 結束完運行的回調 * @parmas delay 規定時間 */ export const throttle = (function () { let timeout = null return function (func, wait) { let context = this let args = arguments if (!timeout) { timeout = setTimeout(() => { timeout = null func.apply(context, args) }, wait) } } })() throttle(fn, 300)
typeFn
類型判斷判斷是不是 Array
Object
String
Number
類型
typeFn.type(value)
參數
type
數據類型value
要檢驗的值示例
typeFn.String('1') typeFn.Number(1) typeFn.Boolean(false) typeFn.Null(null) typeFn.Array([1, 2]) typeFn.Object({ a: 1 }) typeFn.Function(() => {}) // => true
源碼
let typeFn = {} const curring = (fn, arr = []) => { let len = fn.length return (...args) => { arr = arr.concat(args) if (arr.length < len) { return curring(fn, arr) } return fn(...arr) } } function isType(type, content) { return Object.prototype.toString.call(content) === `[object ${type}]` } ;['String', 'Number', 'Boolean', 'Null', 'Array', 'Object', 'Function'].forEach(type => { typeFn[type] = curring(isType)(type) })
calcFn
加減乘除運算由於 JavaScript 遵循 IEEE 754 數學標準,使用 64 位浮點數進行運算。在進行十進制運算時會致使精度丟失。
calcFn.add(value1, value2, value3)
參數
add
、sub
、mul
、div
運算符value
要計算的值示例
解決 0.1+0.2 !== 0.3 問題 //加法 calcFn.add(0.1, 0.2) // 0.3 //減法 calcFn.sub(0.1, 0.2) // 0.1 //乘法 calcFn.mul(0.2, 0.3) // 0.06 // 乘法 calcFn.add(0.1, 0.2) // 0.5
源碼
const calcFn = { add() { let arg = Array.from(arguments); return arg.reduce((total, num) => { return accAdd(total, num); }); }, sub() { let arg = Array.from(arguments); return arg.reduce((total, num) => { return accAdd(total, -num); }); }, mul() { let arg = Array.from(arguments); return arg.reduce((total, num) => { return accMul(total, num); }); }, div() { let arg = Array.from(arguments); return arg.reduce((total, num) => { return accDiv(total, num); }); } } function accAdd(arg1, arg2) { let r1, r2, m; try { r1 = arg1.toString().split(".")[1].length; } catch (e) { r1 = 0; } try { r2 = arg2.toString().split(".")[1].length; } catch (e) { r2 = 0; } m = Math.pow(10, Math.max(r1, r2)); return (arg1 * m + arg2 * m) / m; } function accMul(arg1, arg2) { let m = 0, s1 = arg1.toString(), s2 = arg2.toString(); try { m += s1.split(".")[1].length; } catch (e) {} try { m += s2.split(".")[1].length; } catch (e) {} return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m); } function accDiv(arg1, arg2) { let t1 = 0, t2 = 0, r1, r2; try { t1 = arg1.toString().split(".")[1].length; } catch (e) {} try { t2 = arg2.toString().split(".")[1].length; } catch (e) {} r1 = Number(arg1.toString().replace(".", "")); r2 = Number(arg2.toString().replace(".", "")); return (r1 / r2) * Math.pow(10, t2 - t1); }
isNil
值是不是null
或undefined
isNil(value)
參數
value
要檢驗的值示例
isNil(null) isNil(undefined) // => true
源碼
const isNil = val => val === undefined || val === null
padStart
遮住字符串padStart(value, n, maskChar)
參數
value
要遮住字符串n = 4
填充的長度maskChar
填充字符示例
padStart('18659808664') // => 1865*******
源碼
const padStart = (str, n = 4, maskChar = '*') => str.slice(0, n).padStart(str.length, maskChar)
thousands
數字每隔三位數加分號thousands(number)
參數
number
數字或者浮點數示例
thousands(12255552323) // => 12,255,552323
源碼
const thousands = num => num.toString().replace(num.toString().indexOf('.') > -1 ? /(\d)(?=(\d{3})+\.)/g : /(\d)(?=(\d{3})+$)/g, '$1,')
randomNumber
指定範圍的隨機整數randomNumber(min, max)
參數
min
指定範圍最小值max
指定範圍最大值示例
randomNumber(0, 10) // => 7 // => 2
源碼
const randomNumber = (min = 0, max = 10) => Math.floor(Math.random() * (max - min + 1)) + min
average
求平均值average(value1, value2, value3)
參數
value
數字示例
average(...[1, 2, 3]) average(1, 2, 3) // => 2
源碼
const average = (...nums) => nums.reduce((acc, val) => acc + val, 0) / nums.length
averageBy
檢查數組對象各項相等averageBy(array, fn)
參數
array
要迭代的數組fn
迭代函數示例
averageBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], o => o.n) averageBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], 'n') // => 5
源碼
const averageBy = (arr, fn) => arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val) => acc + val, 0) / arr.length
aboutEqual
兩個值是否約等於傳入兩個數字是否大體相等,偏差在可接受範圍內
aboutEqual(n1, n2, epsilon)
參數
n1 n2
要比較的數字epsilon
偏差可接受範圍內示例
aboutEqual(25, 2, 0.06) // => true
源碼
const aboutEqual = (n1, n2, epsilon = 0.001) => Math.abs(n1 - n2) < epsilon
getLineSize
計算兩點之間的距離勾股定理計算兩點之間的距離
getLineSize = (x1, y1, x2, y2)
參數
x1 y1 x2 y2
座標點示例
getLineSize(0, 0, 3, 4) // => 5
源碼
const getLineSize = (x1, y1, x2, y2) => Math.hypot(x2 - x1, y2 - y1)
sum
數組中值總和sum(value1, value2, value3)
參數
value1 value2 value3
要迭代的數字示例
sum(1, 2, 3, 4) sum(...[1, 2, 3, 4]) // => 10
源碼
const sum = (...arr) => [...arr].reduce((acc, val) => acc + val, 0)
copyText
H5複製文本copyText(content, callback)
參數
content
要複製文字callback
回調用戶提示示例
copyText(content, text => { this.$toast(text) })
源碼
function copyText(content, callback) { if (!document.queryCommandSupported('copy')) { //爲了兼容有些瀏覽器 queryCommandSupported 的判斷 console.log('瀏覽器不支持') return } let textarea = document.createElement('textarea') textarea.value = content textarea.readOnly = 'readOnly' document.body.appendChild(textarea) textarea.select() // 選擇對象 textarea.setSelectionRange(0, content.length) //核心 let result = document.execCommand('copy') // 執行瀏覽器複製命令 callback && callback(result ? '複製成功~~' : '複製失敗~~') textarea.remove() }
getCurrentURL
獲取當前的 URL 地址該函數返回當前頁面的 URL 地址。
示例
getCurrentURL() // =>
源碼
const getCurrentURL = () => window.location.href
scrollToTop
返回頂部平滑地滾動到當前頁面的頂部。
示例
scrollToTop() // => 當前頁面的頂部
源碼
const scrollToTop = () => { const c = document.documentElement.scrollTop || document.body.scrollTop if (c > 0) { window.requestAnimationFrame(scrollToTop) window.scrollTo(0, c - c / 8) } }
smoothScroll
平滑滾動頁面平滑滾動到瀏覽器窗口的可見區域
示例
smoothScroll('#fooBar'); // => 平滑滾動到ID爲fooBar的元素 smoothScroll ('.fooBar' ); // => 使用fooBar類平滑滾動到第一個元素
源碼
const smoothScroll = element => document.querySelector(element).scrollIntoView({ behavior: 'smooth', })
isCurrentPage
是不是當前頁面瀏覽器的選項卡是不是用戶在瀏覽
示例
isCurrentPage() // => true
源碼
isCurrentPage = () => !document.hidden
isBrowser
是不是瀏覽器返回當前運行時環境是否爲瀏覽器
示例
isBrowser() // => true (browser) // => false (Node)
源碼
const isBrowser = () => ![typeof window, typeof document].includes('undefined')
isWechatBrowser
判斷微信瀏覽器仍是普通h5示例
isWechatBrowser() // => true
源碼
const isWechatBrowser = (() => { let ua = navigator.userAgent.toLowerCase() return /micromessenger/.test(ua) })()
isMobile
判斷是不是移動端示例
isMobile() // => true
源碼
const isMobile = () => /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)