快收藏!這些JS數(shù)組小技巧
今天,我想來(lái)聊聊JS處理數(shù)組有哪些小妙招值得我們關(guān)注?
數(shù)組置空
數(shù)組置空?這不是基操嗎?我直接甩一手代碼就問(wèn)怕不怕
let arr = [1,2,3]
arr = []
其實(shí)啊arr=[]是將arr數(shù)據(jù)引用到空數(shù)組[]中,其他引用arr數(shù)據(jù)的變量是不受影響的。這就意味著,數(shù)組先前的內(nèi)容依舊保存在內(nèi)存中,當(dāng)數(shù)據(jù)量比較大時(shí),可以會(huì)造成內(nèi)存泄漏
。那么如何避免類似的隱患?
let arr = [1,2,3]
arr.length = 0
這樣就可以徹底清空arr數(shù)據(jù)的內(nèi)容,先前引用arr數(shù)據(jù)的內(nèi)容也會(huì)一并消失。
數(shù)組頭部插入數(shù)據(jù)
數(shù)據(jù)頭部插入數(shù)據(jù),你是否還在用JS提供的unshift()方法
let arr = [1,2,3]
arr.unshift('我是頭部插入的數(shù)據(jù)')
console.log(arr) // => ['我是頭部插入的數(shù)據(jù)', 1, 2, 3]
現(xiàn)在21世紀(jì)了,得用新的思路去解決問(wèn)題,考慮到性能的問(wèn)題,現(xiàn)在我們可以采用以下的辦法實(shí)現(xiàn)數(shù)組插入數(shù)據(jù)
let arr = [1,2,3]
let newArr = ['haha'].concat(arr)
console.log(newArr) // => ['haha',1, 2, 3]
這樣性能就能比較好?我們口說(shuō)無(wú)憑,直接測(cè)試一下:
let arr = []
console.time('開(kāi)始測(cè)試 100次 數(shù)據(jù)操作時(shí) concat 的性能')
for (let i = 0; i < 100; i++) {
arr.concat(['concat在測(cè)試'])
}
console.timeEnd('開(kāi)始測(cè)試 100次 數(shù)據(jù)操作時(shí) concat 的性能')
console.time('開(kāi)始測(cè)試 100次 數(shù)據(jù)操作時(shí) unshift 的性能')
for (let i = 0; i < 100; i++) {
arr.unshift(['unshift在測(cè)試'])
}
console.timeEnd('開(kāi)始測(cè)試 100次 數(shù)據(jù)操作時(shí) unshift 的性能')
100次數(shù)據(jù)量的耗時(shí)結(jié)果:
10000次數(shù)據(jù)量的耗時(shí)結(jié)果:
100000次數(shù)據(jù)量的耗時(shí)結(jié)果:
這簡(jiǎn)直就是碾壓了 unshift 的速度了。所以我們?cè)诓僮鲾?shù)組頭部插入數(shù)據(jù)的時(shí)候可以選用 let newArr = ['haha'].concat(arr) 這種方式
數(shù)組尾部插入數(shù)據(jù)
同樣的,在數(shù)組尾部插入數(shù)據(jù)你是否還在用這樣的方法?
let arr = [1,2,3]
arr.push(4)
console.log(arr) // => [1,2,3,4]
其實(shí),我們都忽略了數(shù)組本身就很方便的數(shù)據(jù)插入邏輯
let arr = [1,2,3]
arr[arr.length] = 4
console.log(arr) // => [1,2,3,4]
直接上測(cè)試用例
let arr = []
console.time('開(kāi)始測(cè)試 100次 數(shù)據(jù)操作時(shí) push 的性能')
for (let i = 0; i < 100; i++) {
arr.push('push在測(cè)試')
}
console.timeEnd('開(kāi)始測(cè)試 100次 數(shù)據(jù)操作時(shí) push 的性能')
console.time('開(kāi)始測(cè)試 100次 數(shù)據(jù)操作時(shí) length 的性能')
for (let i = 0; i < 100; i++) {
arr[arr.length] = 'length在測(cè)試'
}
console.timeEnd('開(kāi)始測(cè)試 100次 數(shù)據(jù)操作時(shí) length 的性能')
100次數(shù)據(jù)量的耗時(shí)結(jié)果:
10000次數(shù)據(jù)量的耗時(shí)結(jié)果:
100000次數(shù)據(jù)量的耗時(shí)結(jié)果:
可以看到是略勝一點(diǎn),有時(shí)又稍微慢點(diǎn),總體上來(lái)說(shuō) arr[arr.length] = 'length在測(cè)試'會(huì)稍微快點(diǎn)點(diǎn)。
數(shù)組去重
數(shù)組去重這個(gè)方法大家就用得比較多了
let arr = ['9', '1', '2', '3', '4', '5', '1', '3', '2', '6', '2']
console.log(Arry.from(new Set(arr))) // =>['9', '1', '2', '3', '4', '5', '6']
//倘若不用Arry.from()呢?
console.log(new Set(arr)) // => {'9', '1', '2', '3', '4','5','6'}
復(fù)制數(shù)組
利用 擴(kuò)展運(yùn)算法 實(shí)現(xiàn)數(shù)組的復(fù)制。值得注意的是,擴(kuò)展運(yùn)算符 的使用是深拷貝還是淺拷貝得看數(shù)據(jù)源的數(shù)據(jù)類型。如果只是一層數(shù)組或是對(duì)象,其元素只是簡(jiǎn)單類型的元素,那么屬于深拷貝。
let arr = ['張三', '李四', '王五', '找六', '張三']
let test = [...arr] // => 深拷貝
console.log(test) // => ['張三', '李四', '王五', '找六', '張三']
let obj = {
age: 18,
name: '小明',
address: {
city: '東莞'
}
}
let newObj = {...obj}
console.log(newObj.address.city) // => 東莞
由上可見(jiàn),擴(kuò)展運(yùn)算符 還可以將數(shù)組轉(zhuǎn)為對(duì)象
let arr = ['張三', '李四', '王五', '找六', '張三']
let obj = { ...arr }
console.log(obj) // => {0: '張三', 1: '李四', 2: '王五', 3: '找六', 4: '張三'}
合并數(shù)據(jù)
常用的合并數(shù)據(jù) concat 這里就不提了,這里我們使用 擴(kuò)展運(yùn)算符 來(lái)合并數(shù)據(jù)
let arr2 = ['張三', '李四', '王五', '找六', '張三']
let arr3 = ['小明', '小紅', '王五', '張三']
console.log([...arr2, ...arr3]) // => ['張三', '李四', '王五', '找六', '張三', '小明', '小紅', '王五', '張三']
//很明顯這樣的合并不是我們想要的效果,我們需要對(duì)數(shù)組去重
console.log(Array.from(new Set([...arr2, ...arr3])))
// => ['張三', '李四', '王五', '找六', '小明', '小紅']
數(shù)組交集
講到合并必然會(huì)想到交集。回想一下,之前我們?nèi)蓚€(gè)數(shù)組的交集是不是直接遍歷兩個(gè)數(shù)組,然后比較值來(lái)完成的?今天,我們利用 filter 跟ES7的 includes 方法來(lái)完成
let arr2 = ['張三', '李四', '王五', '找六', '張三']
let arr3 = ['小明', '小紅', '王五', '張三']
let jiaoji = [...new Set(arr2)].filter(item => arr3.includes(item)) // => ['張三', '王五']
獲取數(shù)組的隨機(jī)值
使用Math.floor()和Math.random()方法獲得一個(gè)隨機(jī)值
let arr2 = ['張三', '李四', '王五', '找六', '張三']
console.log(arr2[Math.floor(Math.random() * (arr2.length))]) // => 張三
獲取最后出現(xiàn)的下標(biāo)
lastIndexOf 可以幫助我們獲取數(shù)組最后出現(xiàn)字符的下標(biāo)
let arr2 = ['張三', '李四', '王五', '找六', '張三']
console.log(arr2.lastIndexOf('張三')) // => 4
數(shù)組倒序
let arr2 = ['張三', '李四', '王五', '找六']
console.log(arr2.reverse()) // => ['找六', '王五', '李四', '張三']
說(shuō)到 reverse 這里插一句,實(shí)現(xiàn)字符串倒敘可以怎么完成?我們還是利用數(shù)組的 reverse 方法。首先將字符串切割為數(shù)組,然后反轉(zhuǎn)數(shù)組,最后拼接數(shù)組為字符串
let str = 'abcdef'
console.log(atr.split('').reverse().join('')) // => fedcba
替換任意位置的值
splice() 方法從數(shù)組中添加/刪除項(xiàng)目,然后返回被刪除的數(shù)據(jù)。該方法會(huì)改變?cè)紨?shù)組。注意插入值的位置!
let arr2 = ['張三', '李四', '王五', '找六', '張三']
arr2.splice(1, 3, '替換值1', '替換值2', '替換值3')
console.log(arr2) // => ['張三', '替換值1', '替換值2', '替換值3', '張三']
arr2.splice(0, 1) // => 不傳入3+n值的時(shí)候代表刪除數(shù)據(jù)
console.log(arr2) // => ['張三', '替換值1', '替換值2', '替換值3', '張三'] // => ['李四', '王五', '找六', '張三']
遍歷數(shù)組
平時(shí)我們使用最多的就是數(shù)組的 .map 方法,其實(shí)還有一個(gè)方法也能達(dá)到一樣的目的,那就是Array.from
let list = [
{ name: '小明', age: 11 },
{ name: '小紅', age: 13 },
{ name: '校長(zhǎng)', age: 15 }
]
Array.from(list, (item) => item.str = `名字:${item.name},年齡:${item.age}`)
console.log(list)
結(jié)果就是可以直接改變list的數(shù)據(jù):
去掉數(shù)據(jù)中的虛假值
JS中虛假值有:false、0、''、null、NaN、undefined、-0
let arr4 = ['小明', '小藍(lán)', '', false, ' ', undefined, null, 0, NaN, true]
console.log(arr4.filter(Boolean)) // => ['小明', '小藍(lán)', ' ', true]
值得注意的是' ' 并不是虛假值
數(shù)組求和
通常想到的就是直接遍歷數(shù)組,然后累加,其實(shí) reduce 有很多的妙用
let arr2 = ['張三', '李四', '王五', '找六', '張三']
console.log(arr2.reduce((a, b) => a + b)) // => 張三李四王五找六張三
let arr5 = [1, 2, 3, 4]
console.log(arr5.reduce((a, b) => a + b)) // => 10
當(dāng)數(shù)組中純數(shù)字類型的話得到的值是數(shù)字,簡(jiǎn)單類型的字符串的話是字符串
