徒手實(shí)現(xiàn)關(guān)于JavaScript的24+數(shù)組方法
這篇文章會(huì)和你一起探究24+原生數(shù)組方法的內(nèi)部實(shí)現(xiàn),相信你看完一定會(huì)有屬于自己不一樣的收獲。

一、遍歷類(lèi)
1. forEach
基本使用:
forEach一個(gè)日常用的非常多的遍歷函數(shù),你一定熟悉到不能再熟悉啦!這里我們著重看一些比較重要且容易忽略的點(diǎn)。mdn
- 該方法對(duì)數(shù)組的每個(gè)元素執(zhí)行一次給定的函數(shù),返回值是
undefiend - 該方法按升序?yàn)閿?shù)組中含有效值的每一項(xiàng)執(zhí)行一次
callback函數(shù),未初始化的項(xiàng)將被跳過(guò)(例如在稀疏數(shù)組上)。 - 如果已經(jīng)存在的值被改變,則傳遞給
callback的值是forEach()遍歷到他們那一刻的值。 - 已刪除的項(xiàng)不會(huì)被遍歷到
舉個(gè)小例子:
let demoArr = [ 1, 2, 3, 4, , 5 ]
demoArr.forEach((it, i) => {
if (i === 1) {
// 后添加進(jìn)去的不會(huì)被訪問(wèn)到
demoArr.push(5)
} else if (i === 2) {
// 4將不會(huì)被訪問(wèn)到,而4-4會(huì)被訪問(wèn)到
demoArr.splice(3, 1, '4-4')
}
console.log(it)
})
/*
1
2
3
4-4
5
*/
代碼實(shí)現(xiàn):
Array.prototype.forEach2 = function (callback, thisCtx) {
if (typeof callback !== 'function') {
throw `${callback} is not a function`
}
const length = this.length
let i = 0
while (i < length) {
// 被刪除的,新增的元素索引i不在數(shù)組內(nèi),所以不會(huì)被訪問(wèn)到
if (i in this) {
callback.call(thisCtx, this[ i ], i, this)
}
i++
}
}
同樣用剛才的例子,改下后的輸出是一樣的
測(cè)試一把:
// 測(cè)試
let demoArr = [ 1, 2, 3, 4, , 5 ]
demoArr.forEach2((it, i) => {
if (i === 1) {
// 后添加進(jìn)去的不會(huì)被訪問(wèn)到
demoArr.push(5)
} else if (i === 2) {
// 4將不會(huì)被訪問(wèn)到,相仿4-4會(huì)被訪問(wèn)到
demoArr.splice(3, 1, '4-4')
}
console.log(it)
})
/*
1
2
3
4-4
5
*/
2. map
基本使用:
map方法創(chuàng)建一個(gè)新數(shù)組,其結(jié)果是該數(shù)組中的每個(gè)元素是調(diào)用一次提供的函數(shù)后的返回值。mdn
注意點(diǎn):
callback函數(shù)只會(huì)在有值的索引上被調(diào)用- 從來(lái)沒(méi)被賦過(guò)值或者使用 delete 刪除的索引則不會(huì)被調(diào)用。
// 注意索引為2的位置沒(méi)有賦值 let arr = [ 1, 2, ,4, 5 ] // 刪除索引3 delete arr[3] console.log(arr.map((it) => it * it)) // [ 1, 4, 25 ]
代碼實(shí)現(xiàn):
Array.prototype.map2 = function (callback, thisCtx) {
if (typeof callback !== 'function') {
throw `${callback} is not a function`
}
const length = this.length
let i = 0
// map返回值是一個(gè)新的數(shù)組
let newArray = []
while (i < length) {
// 被刪除的,未初始化的都不會(huì)被遍歷到
if (i in this) {
newArray.push(callback.call(thisCtx, this[ i ], i, this))
}
i++
}
// 返回新的數(shù)組
return newArray
}
測(cè)試一把:
let arr = [ 0, 1, 2, 3, 4,, 5 ]
let arr2 = arr.map2(function (it, i, array) {
console.log(it, i, array, this)
return it * it
}, { name: '前端胖頭魚(yú)' })
console.log(arr2)

3. every
基本使用:
every方法測(cè)試一個(gè)數(shù)組內(nèi)的所有元素是否都能通過(guò)某個(gè)指定函數(shù)的測(cè)試。它返回一個(gè)布爾值。mdn
注意點(diǎn):
- 若收到一個(gè)空數(shù)組,此方法在一切情況下都會(huì)返回 true。
- callback 只會(huì)為那些已經(jīng)被賦值的索引調(diào)用
- 不會(huì)為那些被刪除或從未被賦值的索引調(diào)用
// 舉例 let emptyArr = [] // 空數(shù)組直接返回true console.log(emptyArr.every((it) => it > 0)) // true // 有未被賦值的 let arr = [ 0, 1, 2, 3, 4,, 5, -1 ] // 刪除元素 delete arr[7] console.log(arr.every((it) => it >= 0)) // true
代碼實(shí)現(xiàn):
Array.prototype.every2 = function (callback, thisCtx) {
if (typeof callback !== 'function') {
throw `${callback} is not a function`
}
const length = this.length
let i = 0
// 空函數(shù)不會(huì)走進(jìn)循環(huán)
while (i < length) {
// 只要有一個(gè)值不符合callback預(yù)期就返回false
if (i in this && !callback.call(thisCtx, this[ i ], i, this)) {
return false
}
i++
}
return true
}
測(cè)試一把:
還是拿例子做測(cè)試
let emptyArr = [] console.log(emptyArr.every2((it) => it > 0)) // true let arr = [ 0, 1, 2, 3, 4,, 5, -1 ] delete arr[7] console.log(arr.every2((it) => it >= 0)) // true
4. some
基本使用:
some方法測(cè)試數(shù)組中是不是至少有1個(gè)元素通過(guò)了被提供的函數(shù)測(cè)試。它返回的是一個(gè)Boolean類(lèi)型的值。 mdn
注意點(diǎn):
callback只會(huì)在那些”有值“的索引上被調(diào)用,不會(huì)在那些被刪除或從來(lái)未被賦值的索引上調(diào)用。
舉個(gè)例子
let emptyArr = [] // 空數(shù)組直接返回false console.log(emptyArr.some((it) => it > 0)) // false let arr = [ 0, 1, 2, 3, 4,, 5, -1 ] // 還沒(méi)有遍歷前把-1刪除了,唯一小于0的值不存在了,即返回false delete arr[7] console.log(arr.some((it) => it < 0)) // false
代碼實(shí)現(xiàn):
Array.prototype.some2 = function (callback, thisCtx) {
if (typeof callback !== 'function') {
throw `${callback} is not a function`
}
const length = this.length
let i = 0
while (i < length) {
// 只要有一個(gè)元素符合callback條件,就返回true
if (i in this && callback.call(thisCtx, this[ i ], i, this)) {
return true
}
i++
}
return false
}
測(cè)試一把:
let emptyArr = [] // 空數(shù)組直接返回true console.log(emptyArr.some2((it) => it > 0)) // false let arr = [ 0, 1, 2, 3, 4,, 5, -1 ] delete arr[7] console.log(arr.some2((it) => it < 0)) // false console.log(arr.some2((it) => it > 0)) // true
5. filter
基本使用:
filter 方法創(chuàng)建一個(gè)新數(shù)組, 其包含通過(guò)所提供函數(shù)測(cè)試的所有元素。 mdn
注意點(diǎn):
filter為數(shù)組中的每個(gè)元素調(diào)用一次callback函數(shù),并利用所有使得callback返回true或等價(jià)于true的值的元素創(chuàng)建一個(gè)新數(shù)組。callback只會(huì)在已經(jīng)賦值的索引上被調(diào)用,對(duì)于那些已經(jīng)被刪除或者從未被賦值的索引不會(huì)被調(diào)用。- 那些沒(méi)有通過(guò)
callback測(cè)試的元素會(huì)被跳過(guò),不會(huì)被包含在新數(shù)組中。
// 索引為5的位置,沒(méi)有初始化值,不會(huì)被遍歷 let arr = [ 0, 1, 2, -3, 4,, 5 ] // 刪除掉最后一個(gè)元素 delete arr[6] // 過(guò)濾出大于0的值 let filterArr = arr.filter((it) => it > 0) console.log(filterArr) // [ 1, 2, 4 ]
代碼實(shí)現(xiàn):
Array.prototype.filter2 = function (callback, thisCtx) {
if (typeof callback !== 'function') {
throw `${callback} is not a function`
}
const length = this.length
let newArray = []
let i = 0
while (i < length) {
if (i in this && callback.call(thisCtx, this[ i ], i, this)) {
newArray.push(this[ i ])
}
i++
}
return newArray
}
測(cè)試:
// 索引為5的位置,沒(méi)有初始化值,不會(huì)被遍歷 let arr = [ 0, 1, 2, -3, 4,, 5 ] // 刪除掉最后一個(gè)元素 delete arr[6] // 過(guò)濾出大于0的值 let filterArr = arr.filter2((it) => it > 0) console.log(filterArr) // [ 1, 2, 4 ]
6. reduce
基本使用:
reduce方法對(duì)數(shù)組中的每個(gè)元素執(zhí)行一個(gè)由您提供的reducer函數(shù)(升序執(zhí)行),將其結(jié)果匯總為單個(gè)返回值 mdn
這個(gè)函數(shù)稍微復(fù)雜一些,我們用一個(gè)例子來(lái)看一下他是怎么用的。
const sum = [1, 2, 3, 4].reduce((prev, cur) => {
return prev + cur;
})
console.log(sum) // 10
// 初始設(shè)置
prev = initialValue = 1, cur = 2
// 第一次迭代
prev = (1 + 2) = 3, cur = 3
// 第二次迭代
prev = (3 + 3) = 6, cur = 4
// 第三次迭代
prev = (6 + 4) = 10, cur = undefined (退出)
代碼實(shí)現(xiàn):
Array.prototype.reduce2 = function (callback, initValue) {
if (typeof callback !== 'function') {
throw `${callback} is not a function`
}
let pre = initValue
let i = 0
const length = this.length
// 當(dāng)沒(méi)有傳遞初始值時(shí),取第一個(gè)作為初始值
if (typeof pre === 'undefined') {
pre = this[0]
i = 1
}
while (i < length) {
if (i in this) {
pre = callback(pre, this[ i ], i, this)
}
i++
}
return pre
}
測(cè)試:
const sum = [1, 2, 3, 4].reduce2((prev, cur) => {
return prev + cur;
})
console.log(sum) // 10
7. reduceRight
基本使用:
reduceRight方法對(duì)數(shù)組中的每個(gè)元素執(zhí)行一個(gè)由您提供的reducer函數(shù)(降序執(zhí)行),將其結(jié)果匯總為單個(gè)返回值 mdn
和reduce很類(lèi)似,唯一不同的是reduceRight從右往左遍歷
const sum = [1, 2, 3, 4].reduce((prev, cur) => {
console.log(cur)
return prev + cur;
})
// 2 1
// 3 2
// 4 3
console.log(sum) // 10
const sum2 = [1, 2, 3, 4].reduceRight((prev, cur) => {
console.log(cur)
return prev + cur;
})
// 3 2
// 2 1
// 1 0
console.log(sum2) // 10
代碼實(shí)現(xiàn):
Array.prototype.reduceRight2 = function (callback, initValue) {
if (typeof callback !== 'function') {
throw `${callback} is not a function`
}
let pre = initValue
const length = this.length
// 從最后一個(gè)元素開(kāi)始遍歷
let i = length - 1
// 如果沒(méi)有傳遞初始值,則取最后一個(gè)作為初始值
if (typeof pre === 'undefined') {
pre = this[i]
i--
}
while (i >= 0) {
if (i in this) {
pre = callback(pre, this[ i ], i, this)
}
i--
}
return pre
}
測(cè)試:
const sum = [1, 2, 3, 4].reduceRight2((prev, cur) => {
console.log(cur)
return prev + cur;
})
// 3 2
// 2 1
// 1 0
console.log(sum) // 10
二、查找類(lèi)
1. find
基本使用:
find 方法返回?cái)?shù)組中滿(mǎn)足測(cè)試函數(shù)的第一個(gè)元素的值。否則返回
undefined, mdn
注意點(diǎn):
find方法對(duì)數(shù)組中的每一項(xiàng)元素執(zhí)行一次callback函數(shù),直至有一個(gè)callback返回 true- 當(dāng)找到了這樣一個(gè)元素后,該方法會(huì)立即返回這個(gè)元素的值,否則返回
undefined callback函數(shù)會(huì)為數(shù)組中的每個(gè)索引調(diào)用即從 0 到length - 1,而不僅僅是那些被賦值的索引。(這個(gè)點(diǎn)是和前面幾個(gè)函數(shù)不一樣的地方)
let arr = [ 0, 1, 2, 3, 4,, 5 ]
let index = arr.find((it) => {
return it > 3
}, { name: '前端胖頭魚(yú)' })
console.log(index) // 4
代碼實(shí)現(xiàn):
Array.prototype.find2 = function (callback, thisCtx) {
if (typeof callback !== 'function') {
throw `${callback} is not a function`
}
const length = this.length
let i = 0
while (i < length) {
const value = this[ i ]
// 只要有一個(gè)元素符合callback回調(diào)函數(shù)的邏輯,就返回元素value
if (callback.call(thisCtx, value, i, this)) {
return value
}
i++
}
// 否則返回undefined
return undefined
}
測(cè)試:
let arr = [ 0, 1, 2, 3, 4,, 5 ]
let index = arr.find2(function (it, i, array) {
console.log(it, i, array, this)
return it > 3
}, { name: '前端胖頭魚(yú)' })
console.log(index) // 4

2. findIndex
基本使用:
findIndex方法返回?cái)?shù)組中滿(mǎn)足提供的測(cè)試函數(shù)的第一個(gè)元素的索引。若沒(méi)有找到對(duì)應(yīng)元素則返回-1。 mdn- 和find函數(shù)不同的地方在于,
findIndex是返回索引而非值, 注意點(diǎn)也和find基本一樣 - findIndex方法對(duì)數(shù)組中的每個(gè)數(shù)組索引0 ~ length-1(包括)執(zhí)行一次callback函數(shù),直到找到一個(gè)
callback函數(shù)返回true的值。 - 如果找到這樣的元素,findIndex會(huì)立即返回該元素的索引。如果回調(diào)從不返回真值,或者數(shù)組的
length為0,則findIndex返回-1 - 與某些其他數(shù)組方法(如
Array#some)不同,在稀疏數(shù)組中,即使對(duì)于數(shù)組中不存在的條目的索引也會(huì)調(diào)用回調(diào)函數(shù)
let arr = [ 0, 1, 2, 3, 4,, 5 ]
let index = arr.findIndex((it, i, array) => {
return it > 2
})
console.log(index) // 3
代碼實(shí)現(xiàn):
Array.prototype.findIndex2 = function (callback, thisCtx) {
if (typeof callback !== 'function') {
throw `${callback} is not a function`
}
const length = this.length
let i = 0
while (i < length) {
// 符合callback邏輯的直接返回索引i
if (callback.call(thisCtx, this[ i ], i, this)) {
return i
}
i++
}
// 否則返回-1
return -1
}
測(cè)試:
let arr = [ 0, 1, 2, 3, 4,, 5 ]
let index = arr.findIndex2(function (it, i, array) {
console.log(it, i, array, this)
return it > 2
}, { name: '前端胖頭魚(yú)' })
console.log(index) // 3

3. indexOf
基本使用:
indexOf方法返回在數(shù)組中可以找到一個(gè)給定元素的第一個(gè)索引,如果不存在,則返回-1。 mdn
arr.indexOf(searchElement[, fromIndex])
注意點(diǎn):
- 如果開(kāi)始查找的索引值大于或等于數(shù)組長(zhǎng)度,意味著不會(huì)在數(shù)組里查找,返回-1
- 如果參數(shù)中提供的索引值是一個(gè)負(fù)值,則將其作為數(shù)組末尾的一個(gè)抵消,即-1表示從最后一個(gè)元素開(kāi)始查找,-2表示從倒數(shù)第二個(gè)元素開(kāi)始查找 ,以此類(lèi)推
- 如果參數(shù)中提供的索引值是一個(gè)負(fù)值,并不改變其查找順序,查找順序仍然是從前向后查詢(xún)數(shù)組
- 如果抵消后的索引值仍小于0,則整個(gè)數(shù)組都將會(huì)被查詢(xún)。其默認(rèn)值為0.
const array = [2, 5, 9] console.log(array.indexOf(2)) // 0 console.log(array.indexOf(7)) // -1 console.log(array.indexOf(9, 2)) // 2 console.log(array.indexOf(2, -1)) // -1 console.log(array.indexOf(2, -3)) // 0
代碼實(shí)現(xiàn):
有了上面的注意點(diǎn)和基本你使用,聰明的你肯定一眼就知道怎么寫(xiě)啦
Array.prototype.indexOf2 = function (targetEle, fromIndex) {
const length = this.length
fromIndex = +fromIndex || 0
// 數(shù)組為空或者從大于等于數(shù)組長(zhǎng)度的地方開(kāi)始檢索,都直接是-1
if (length === 0 || fromIndex >= length) {
return -1
}
/*
1. 從fromIndex開(kāi)始搜索元素
2. fromIndex大于0時(shí)候直接取即可
3. 小于0先用長(zhǎng)度減去fromIndex的絕對(duì)值,如果還是小于0,就直接取0即可
*/
let i = Math.max(fromIndex >= 0 ? fromIndex : length - Math.abs(fromIndex), 0)
while (i < length) {
// 在數(shù)組內(nèi)的元素并且和targetEle強(qiáng)等
if (i in this && targetEle === this[ i ]) {
return i
}
i++
}
return -1
}
測(cè)試:
const array = [2, 5, 9] console.log(array.indexOf2(2)) // 0 console.log(array.indexOf2(7)) // -1 console.log(array.indexOf2(9, 2)) // 2 console.log(array.indexOf2(2, -1)) // -1 console.log(array.indexOf2(2, -3)) // 0
4. lastIndexOf
基本使用:
lastIndexOf方法返回指定元素在數(shù)組中的最后一個(gè)的索引,如果不存在則返回 -1。 mdn
arr.lastIndexOf(searchElement[, fromIndex])
注意點(diǎn):
- 從
arr.length - 1位置開(kāi)始逆向查找。 - 如果
fromIndex大于或等于數(shù)組的長(zhǎng)度,則整個(gè)數(shù)組會(huì)被查找。 - 如果
fromIndex為負(fù)值,將其視為從數(shù)組末尾向前的偏移。即使該值為負(fù),數(shù)組仍然會(huì)被從后向前查找。 - 如果
fromIndex值為負(fù)時(shí),其絕對(duì)值大于數(shù)組長(zhǎng)度,則方法返回 -1,即數(shù)組不會(huì)被查找。
let array = [2, 5, 9, 2] console.log(array.lastIndexOf(2)) // 3 console.log(array.lastIndexOf(7)) // -1 console.log(array.lastIndexOf(2, 3)) // 3 console.log(array.lastIndexOf(2, 2)) // 0 console.log(array.lastIndexOf(2, -2)) // 0 console.log(array.lastIndexOf(2, -1)) // 3
代碼實(shí)現(xiàn):
Array.prototype.lastIndexOf2 = function (targetEle, fromIndex) {
const length = this.length
fromIndex = typeof fromIndex === 'undefined' ? length - 1 : fromIndex
// 數(shù)組為空,以及該值為負(fù)時(shí)且絕對(duì)值大于數(shù)組長(zhǎng)度,則方法返回 -1,即數(shù)組不會(huì)被查找。
if (length === 0 || fromIndex < 0 && Math.abs(fromIndex) >= length) {
return -1
}
let i
if (fromIndex >= 0) {
// 如果`fromIndex`大于或等于數(shù)組的長(zhǎng)度,則整個(gè)數(shù)組會(huì)被查找。
// 也就是當(dāng)大于數(shù)組length - 1時(shí),會(huì)取length - 1
i = Math.min(fromIndex, length - 1)
} else {
i = length - Math.abs(fromIndex)
}
while (i >= 0) {
// 等于targetEle時(shí)返回索引
if (i in this && targetEle === this[ i ]) {
return i
}
// 逆向遍歷
i--
}
// 沒(méi)找到返回-1
return -1
}
測(cè)試:
let array = [2, 5, 9, 2] console.log(array.lastIndexOf2(2)) // 3 console.log(array.lastIndexOf2(7)) // -1 console.log(array.lastIndexOf2(2, 3)) // 3 console.log(array.lastIndexOf2(2, 2)) // 0 console.log(array.lastIndexOf2(2, -2)) // 0 console.log(array.lastIndexOf2(2, -1)) // 3
5. includes
基本使用:
includes方法用來(lái)判斷一個(gè)數(shù)組是否包含一個(gè)指定的值,如果包含則返回 true,否則返回false。mdn
arr.includes(valueToFind[, fromIndex])
注意點(diǎn):
- 從fromIndex 索引處開(kāi)始查找
valueToFind。 - 如果為負(fù)值,則按升序從
array.length + fromIndex的索引開(kāi)始搜 - 數(shù)組中存在NaN的話
,[ ..., NaN ].includes(NaN)為true
console.log([1, 2, 3].includes(2)) // true console.log([1, 2, 3].includes(4)) // false console.log([1, 2, 3].includes(3, 3)) // false console.log([1, 2, 3].includes(3, -1)) // true console.log([1, 2, NaN].includes(NaN)) // true
代碼實(shí)現(xiàn):
Array.prototype.includes2 = function (targetEle, fromIndex) {
const length = this.length
fromIndex = +fromIndex || 0
// 數(shù)組為空或者從大于等于數(shù)組長(zhǎng)度的地方開(kāi)始檢索,都直接是-1
if (length === 0 || fromIndex >= length) {
return false
}
/*
1. 從fromIndex開(kāi)始搜索元素
2. fromIndex大于0時(shí)候直接取即可
3. 小于0先用長(zhǎng)度減去fromIndex的絕對(duì)值,如果還是小于0,就直接取0即可
*/
let i = Math.max(fromIndex >= 0 ? fromIndex : length - Math.abs(fromIndex), 0)
while (i < length) {
const value = this[ i ]
// 注意NaN情況
if (targetEle === value || typeof targetEle === 'number' && typeof value === 'number' && isNaN(targetEle) && isNaN(value)) {
return true
}
i++
}
return false
}
測(cè)試:
console.log([1, 2, 3].includes2(2)) // true
console.log([1, 2, 3].includes2(4)) // false
console.log([1, 2, 3].includes2(3, 3)) // false
console.log([1, 2, 3].includes2(3, -1)) // true
console.log([1, 2, NaN].includes2(NaN)) // true
三、增刪改類(lèi)
1. push
基本使用:
push方法將一個(gè)或多個(gè)元素添加到數(shù)組的末尾,并返回該數(shù)組的新長(zhǎng)度。mdn
const animals = ['pigs', 'goats', 'sheep']
animals.push('cows')
console.log(animals, animals.length)
// ["pigs", "goats", "sheep", "cows"], 4
animals.push('chickens', 'cats', 'dogs')
console.log(animals, animals.length)
// ["pigs", "goats", "sheep", "cows", "chickens", "cats", "dogs"], 7
代碼實(shí)現(xiàn):
Array.prototype.push2 = function (...pushEles) {
const pushEleLength = pushEles.length
const length = this.length
let i = 0
while (i < pushEleLength) {
this[ length + i ] = pushEles[ i ]
i++
}
return this.length
}
測(cè)試:
const animals = ['pigs', 'goats', 'sheep']
animals.push2('cows')
console.log(animals, animals.length)
// ["pigs", "goats", "sheep", "cows"], 4
animals.push2('chickens', 'cats', 'dogs')
console.log(animals, animals.length)
// ["pigs", "goats", "sheep", "cows", "chickens", "cats", "dogs"], 7
2. pop
基本使用:
pop方法從數(shù)組中刪除最后一個(gè)元素,并返回該元素的值。此方法更改數(shù)組的長(zhǎng)度。mdn
let arr = [ 1, 2 ] let arr2 = [] console.log(arr.pop(), arr) // 2 [1] console.log(arr2.pop(), arr2) // undefined []
代碼實(shí)現(xiàn)和使用一樣簡(jiǎn)單,只要把數(shù)組的最后一個(gè)元素返回,并且讓數(shù)組長(zhǎng)度減1即可
代碼實(shí)現(xiàn):
Array.prototype.pop2 = function () {
const length = this.length
// 空數(shù)組上pop,直接返回undefined
if (length === 0) {
return undefined
}
const delEle = this[ length - 1 ]
this.length = length - 1
return delEle
}
測(cè)試:
let arr = [ 1, 2 ] let arr2 = [] console.log(arr.pop2(), arr) // 2 [1] console.log(arr2.pop2(), arr2) // undefined []
3. unshift
基本使用:
unshift方法將一個(gè)或多個(gè)元素添加到數(shù)組的開(kāi)頭,并返回該數(shù)組的新長(zhǎng)度(該方法修改原有數(shù)組 ) 。
注意點(diǎn):
- 如果傳入多個(gè)參數(shù),它們會(huì)被以塊的形式插入到對(duì)象的開(kāi)始位置,它們的順序和被作為參數(shù)傳入時(shí)的順序一致。
- 傳入多個(gè)參數(shù)調(diào)用一次 unshift ,和傳入一個(gè)參數(shù)調(diào)用多次 unshift (例如,循環(huán)調(diào)用),它們將得到不同的結(jié)果。
例如:
let arr = [4,5,6] // 一次性插入 arr.unshift(1,2,3) console.log(arr) // [1, 2, 3, 4, 5, 6] let arr2 = [4,5,6] // 插入多次 arr2.unshift(1) arr2.unshift(2) arr2.unshift(3) console.log(arr2); // [3, 2, 1, 4, 5, 6]
代碼實(shí)現(xiàn):
Array.prototype.unshift2 = function (...unshiftEles) {
// 借助擴(kuò)展符,將需要添加的元素以塊的形式插入到數(shù)組前面
let newArray = [ ...unshiftEles, ...this ]
let length = newArray.length
let i = 0
if (unshiftEles.length === 0) {
return length
}
// 重新復(fù)制給數(shù)組
while (i < length) {
this[ i ] = newArray[ i ]
i++
}
return this.length
}
測(cè)試:
let arr = [4,5,6] // 一次性插入 arr.unshift2(1,2,3) console.log(arr) // [1, 2, 3, 4, 5, 6] let arr2 = [4,5,6] // 插入多次 arr2.unshift2(1) arr2.unshift2(2) arr2.unshift2(3) console.log(arr2); // [3, 2, 1, 4, 5, 6]
4. shift
基本使用:
shift 方法從數(shù)組中刪除第一個(gè)元素,并返回該元素的值。 mdn
let arr = [ 1, 2 ] console.log(arr.shift(), arr) // 1 [2] console.log(arr.shift(), arr) // 2 []
代碼實(shí)現(xiàn):
Array.prototype.shift2 = function () {
const length = this.length
const delValue = this[ 0 ]
let i = 1
while (i < length) {
// 從第一個(gè)元素開(kāi)始,后面的元素都往前移動(dòng)一位
this[ i - 1 ] = this[ i ]
i++
}
// 設(shè)置好數(shù)組的長(zhǎng)度
this.length = length - 1
// 返回刪除的值
return delValue
}
測(cè)試:
let arr = [ 1, 2 ] console.log(arr.shift2(), arr) // 1 [2] console.log(arr.shift2(), arr) // 2 []
5. reverse
基本使用:
reverse方法將數(shù)組中元素的位置顛倒,并返回該數(shù)組。即數(shù)組的第一個(gè)元素會(huì)變成最后一個(gè),數(shù)組的最后一個(gè)元素變成第一個(gè)。mdn
``` javascript const arr = [1, 2, 3] console.log(arr) // [1, 2, 3] arr.reverse() console.log(arr) // [3, 2, 1]
代碼實(shí)現(xiàn):
Array.prototype.reverse2 = function () {
// 設(shè)置雙指針,往中間靠攏
let i = 0
let j = this.length - 1
while (i < j) {
// 第一個(gè)和最后一個(gè),第二個(gè)和倒數(shù)第二個(gè)進(jìn)行位置調(diào)換
[ this[ i ], this[ j ] ] = [ this[ j ], this[ i ] ]
i++
j--
}
return this
}
測(cè)試:
const arr = [1, 2, 3] console.log(arr) // [1, 2, 3] arr.reverse2() console.log(arr) // [3, 2, 1]
6. fill
基本使用:
fill方法用一個(gè)固定值填充一個(gè)數(shù)組中從起始索引到終止索引內(nèi)的全部元素。不包括終止索引。mdn
const array1 = [1, 2, 3, 4]; console.log(array1.fill(0, 2, 4)) // [1, 2, 0, 0] console.log(array1.fill(5, 1)) // [1, 5, 5, 5] console.log(array1.fill(6)) // [6, 6, 6, 6]
代碼實(shí)現(xiàn):
Array.prototype.fill2 = function (value, start, end) {
const length = this.length
start = start >> 0
// end沒(méi)填的話,默認(rèn)是length,否則取填寫(xiě)的
end = typeof end === 'undefined' ? length : end >> 0
// start最小取0,最大取length
start = start >= 0 ? Math.min(start, length) : Math.max(start + length, 0)
// end最小取0,最大取length
end = end >= 0 ? Math.min(end, length) : Math.max(end + length, 0)
// 填充指定范圍的索引為value
while (start < end) {
this[ start ] = value
start++
}
// 返回被修改的數(shù)組
return this
}
測(cè)試:
const array1 = [1, 2, 3, 4]; console.log(array1.fill2(0, 2, 4)) // [1, 2, 0, 0] console.log(array1.fill2(5, 1)) // [1, 5, 5, 5] console.log(array1.fill2(6)) // [6, 6, 6, 6] 連接、拼接
7. concat
基本使用:
concat方法用于合并兩個(gè)或多個(gè)數(shù)組。此方法不會(huì)更改現(xiàn)有數(shù)組,而是返回一個(gè)新數(shù)組 mdn
let num1 = [[1]] let num2 = [2, [3]] let num3=[5,[6]] let nums = num1.concat(num2) // [[1], 2, [3]] let nums2 = num1.concat(4, num3) // [[1], 4, 5,[6]]
代碼實(shí)現(xiàn):
Array.prototype.concat2 = function (...concatEles) {
const length = concatEles.length
// 數(shù)組本身展開(kāi)一層
let newArray = [ ...this ]
let i = 0
while (i < length) {
const value = concatEles[ i ]
// 對(duì)數(shù)組元素展開(kāi)一層
Array.isArray(value) ? newArray.push(...value) : newArray.push(value)
i++
}
return newArray
}
測(cè)試:
let num1 = [[1]] let num2 = [2, [3]] let num3=[5,[6]] let nums = num1.concat2(num2) // [[1], 2, [3]] let nums2 = num1.concat2(4, num3) // [[1], 4, 5,[6]]
8. join
基本使用:
join方法將一個(gè)數(shù)組的所有元素通過(guò)字符標(biāo)識(shí)連接成一個(gè)字符串并返回這個(gè)字符串。如果數(shù)組只有一個(gè)項(xiàng)目,那么將返回該項(xiàng)目而不使用分隔符。
const elements = ['Fire', 'Air', 'Water']
const elements2 = ['Fire']
console.log(elements.join()) // Fire,Air,Water
console.log(elements.join('')) // FireAirWater
console.log(elements.join('-')) // Fire-Air-Water
console.log(elements2.join('-')) // Fire
代碼實(shí)現(xiàn):
Array.prototype.join2 = function (format = ',') {
const length = this.length
// 保存最后一個(gè)元素,因?yàn)樗粎⑴cformat連接
let lastEle = this[ length - 1 ]
let string = ''
if (length === 0) {
return string
}
for (i = 0; i < length - 1; i++) {
string += this[ i ] + format
}
return string + lastEle
}
測(cè)試:
const elements = ['Fire', 'Air', 'Water']
const elements2 = ['Fire']
console.log(elements.join2()) // Fire,Air,Water
console.log(elements.join2('')) // FireAirWater
console.log(elements.join2('-')) // Fire-Air-Water
console.log(elements2.join2('-')) // Fire
四、靜態(tài)方法
1. Array.isArray
基本使用:
Array.isArray()用于確定傳遞的值是否是一個(gè) Array。
Array.isArray([1, 2, 3]) // true
Array.isArray({foo: 123}) // false
Array.isArray("foobar") // false
Array.isArray(undefined) // false
代碼實(shí)現(xiàn):
這個(gè)非常簡(jiǎn)單,只需要一句話就可以
Array.isArray2 = function (ele) {
return Object.prototype.toString.call(ele) === '[object Array]';
}
測(cè)試:
Array.isArray2([1, 2, 3]) // true
Array.isArray2({foo: 123}) // false
Array.isArray2("foobar") // false
Array.isArray2(undefined) // false
2. Array.of
基本使用:
Array.of 方法創(chuàng)建一個(gè)具有可變數(shù)量參數(shù)的新數(shù)組實(shí)例,而不考慮參數(shù)的數(shù)量或類(lèi)型。
注意點(diǎn):
Array.of()和 Array 構(gòu)造函數(shù)之間的區(qū)別在于處理整數(shù)參數(shù):Array.of(7)創(chuàng)建一個(gè)具有單個(gè)元素 7 的數(shù)組,而 Array(7) 創(chuàng)建一個(gè)長(zhǎng)度為7的空數(shù)組(注意: 這是指一個(gè)有7個(gè)空位(empty)的數(shù)組,而不是由7個(gè)undefined組成的數(shù)組)
Array.of(7); // [7] Array.of(1, 2, 3); // [1, 2, 3] Array(7); // [ , , , , , , ] Array(1, 2, 3); // [1, 2, 3]
代碼實(shí)現(xiàn):
實(shí)現(xiàn)思路就是把你穿進(jìn)去的值,挨個(gè)賦值到當(dāng)前數(shù)組即可
Array.of2 = function (...eles) {
const length = eles.length
let i = 0
let newArray = []
while (i < length) {
newArray[ i ] = eles[ i ]
i++
}
return newArray
}
測(cè)試:
Array.of2(7); // [7] Array.of2(1, 2, 3); // [1, 2, 3]
五、扁平類(lèi)
1. flat
基本使用:
flat()方法會(huì)按照一個(gè)可指定的深度遞歸遍歷數(shù)組,并將所有元素與遍歷到的子數(shù)組中的元素合并為一個(gè)新數(shù)組返回。 mdn
const arr1 = [0, 1, 2, [3, 4]]; console.log(arr1.flat()) // [0, 1, 2, 3, 4] 默認(rèn)會(huì)平鋪展開(kāi)一層 const arr2 = [0, 1, 2, [[[3, 4]]]] console.log(arr2.flat(2)) // [0, 1, 2, [3, 4]] 指定展開(kāi)兩層
代碼實(shí)現(xiàn):
Array.prototype.flat2 = function (depth = 1) {
const result = []
const flat = (arr, depth) => {
for (let item of arr) {
// 當(dāng)層數(shù)還未全部展開(kāi)的時(shí)候,進(jìn)行遞歸處理
if (Array.isArray(item) && depth > 0) {
flat(item, depth - 1)
} else {
// 去除空元素,添加非undefined元素
item !== void 0 && result.push(item)
}
}
}
flat(this, depth)
return result
}
測(cè)試:
const arr1 = [0, 1, 2, [3, 4]]; console.log(arr1.flat2()) // [0, 1, 2, 3, 4] const arr2 = [0, 1, 2, [[[3, 4]]]] console.log(arr2.flat2(2)) // [0, 1, 2, [3, 4]]
2. flatMap
基本使用:
flatMap方法首先使用映射函數(shù)映射每個(gè)元素,然后將結(jié)果壓縮成一個(gè)新數(shù)組。它與 map 連著深度值為1的 flat 幾乎相同。 mdn
let arr = [1, 2, 3, 4] arr.flatMap(x => [x * 2]) // [2, 4, 6, 8]
代碼實(shí)現(xiàn):
Array.prototype.flatMap2 = function (callback, thisCtx) {
if (typeof callback !== 'function') {
throw `${callback} is not a function`
}
// map和flat具體實(shí)現(xiàn)可以看map.js和flat.js
return this.map(function (it, i, array) {
return callback.call(thisCtx, it, i, array)
}).flat(1)
}
測(cè)試:
let arr = [1, 2, 3, 4] arr.flatMap2(x => [x * 2]) // [2, 4, 6, 8]
結(jié)尾:
到此這篇關(guān)于徒手實(shí)現(xiàn)關(guān)于JavaScript的24+數(shù)組方法的文章就介紹到這了,更多相關(guān)實(shí)現(xiàn)關(guān)于JavaScript的24+數(shù)組方法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
國(guó)慶將至,祝大家節(jié)日快樂(lè),浪浪浪七天樂(lè)。
- 一篇文章帶你詳細(xì)了解JavaScript數(shù)組
- Javascript數(shù)組去重的幾種方法詳解
- javascript數(shù)組的內(nèi)置方法詳解
- 常用的JavaScript數(shù)組方法
- JavaScript數(shù)組詳細(xì)歸納
- JavaScript常用數(shù)組去重實(shí)戰(zhàn)源碼
- JavaScript如何監(jiān)測(cè)數(shù)組的變化
- JS對(duì)象數(shù)組去重的3種方法示例及對(duì)比
- JS實(shí)現(xiàn)數(shù)組過(guò)濾從簡(jiǎn)單到多條件篩選
- JavaScript數(shù)組reduce()方法的語(yǔ)法與實(shí)例解析
相關(guān)文章
autojs長(zhǎng)寬不定的圖片在正方形圖片居中實(shí)現(xiàn)詳解
這篇文章主要為大家介紹了autojs長(zhǎng)寬不定的圖片在正方形圖片居中實(shí)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
微信小程序 ES6Promise.all批量上傳文件實(shí)現(xiàn)代碼
這篇文章主要介紹了微信小程序 ES6Promise.all批量上傳文件實(shí)現(xiàn)代碼的相關(guān)資料,需要的朋友可以參考下2017-04-04
微信小程序 sha1 實(shí)現(xiàn)密碼加密實(shí)例詳解
這篇文章主要介紹了微信小程序 sha1 實(shí)現(xiàn)密碼加密實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-07-07
TypeScript?泛型推斷實(shí)現(xiàn)示例詳解
這篇文章主要為大家介紹了TypeScript?泛型推斷實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08
微信小程序 網(wǎng)絡(luò)API發(fā)起請(qǐng)求詳解
這篇文章主要介紹了微信小程序 網(wǎng)絡(luò)API發(fā)起請(qǐng)求詳解的相關(guān)資料,需要的朋友可以參考下2016-11-11

