Javascript 高效開發工具庫
前端開發中經常會遇到Array
、Object
、String
、Number
等數據處理,或者是防抖節流函數等性能優化,抑或 URL 參數處理、類型判斷等等操作,爲了提高開發效率,我將這些常見公共方法進行抽離並封裝好,發佈在 npm 上,後續如有更優的寫法也會做進一步的更新。另外讀者朋友們如果有好的建議或者想爲本項目貢獻一份力的話,歡迎爲本項目提交 pr,一起探討和交流。
安裝
$ 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
去除數組中的無效值
對象
-
isObjectEqual
檢查兩個對象各項值相等 -
cloneObject
克隆對象
函數
-
debounce
函數防抖 -
throttle
函數節流 -
typeFn
類型判斷 -
calcFn
加減乘除運算
字符串
-
isNil
值是否是null
或undefined
-
padStart
遮住字符串 -
thousands
數字每隔三位數加分號
數字
-
randomNumber
指定範圍的隨機整數 -
average
求平均值 -
averageBy
檢查數組對象各項相等 -
aboutEqual
兩個值是否約等於 -
getLineSize
計算兩點之間的距離 -
sum
數組中值總和
瀏覽器
-
copyText
H5 複製文本 -
getCurrentURL
獲取當前的 URL 地址 -
scrollToTop
返回頂部 -
smoothScroll
平滑滾動頁面 -
isCurrentPage
是否是當前頁面
由於文章篇幅過長,公衆號上只截取重點部分,如果需要最新完整版,請點擊「閱讀原文」跳到
GitHub
倉庫進行查看
如果對本文有啥疑問或建議,歡迎加我微信
qqlcx55
一起學習哈
一、數組
multArray
二維數組轉換
將數組(array)拆分成多個子數組,並將這些子數組組成一個新數組。
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)拆分成一個數組
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
多層嵌套數組 2.depth = 1
減少的嵌套層級數
示例
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=1
要提取的元素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=1
要提取的元素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(12255555.2323)
// => 12,255,555.2323
源碼
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(1.25, 1.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',
})
參考資料
-
30 seconds of code
-
lodash
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/X4quZULOFgjC1Nk1zNzFyw