徒手實(shí)現(xiàn)關(guān)于JavaScript的24+數(shù)組方法
這篇文章會(huì)和你一起探究24+原生數(shù)組方法的內(nèi)部實(shí)現(xiàn),相信你看完一定會(huì)有屬于自己不一樣的收獲。
一、遍歷類
1. forEach
基本使用:
forEach
一個(gè)日常用的非常多的遍歷函數(shù),你一定熟悉到不能再熟悉啦!這里我們著重看一些比較重要且容易忽略的點(diǎn)。mdn
- 該方法對(duì)數(shù)組的每個(gè)元素執(zhí)行一次給定的函數(shù),返回值是
undefiend
- 該方法按升序?yàn)閿?shù)組中含有效值的每一項(xiàng)執(zhí)行一次
callback
函數(shù),未初始化的項(xiàng)將被跳過(例如在稀疏數(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ì)被訪問到 demoArr.push(5) } else if (i === 2) { // 4將不會(huì)被訪問到,而4-4會(huì)被訪問到 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ì)被訪問到 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ì)被訪問到 demoArr.push(5) } else if (i === 2) { // 4將不會(huì)被訪問到,相仿4-4會(huì)被訪問到 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)用- 從來沒被賦過值或者使用 delete 刪除的索引則不會(huì)被調(diào)用。
// 注意索引為2的位置沒有賦值 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: '前端胖頭魚' }) console.log(arr2)
3. every
基本使用:
every
方法測(cè)試一個(gè)數(shù)組內(nèi)的所有元素是否都能通過某個(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è)元素通過了被提供的函數(shù)測(cè)試。它返回的是一個(gè)Boolean
類型的值。 mdn
注意點(diǎn):
callback
只會(huì)在那些”有值“的索引上被調(diào)用,不會(huì)在那些被刪除或從來未被賦值的索引上調(diào)用。
舉個(gè)例子
let emptyArr = [] // 空數(shù)組直接返回false console.log(emptyArr.some((it) => it > 0)) // false let arr = [ 0, 1, 2, 3, 4,, 5, -1 ] // 還沒有遍歷前把-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ù)組, 其包含通過所提供函數(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)用。- 那些沒有通過
callback
測(cè)試的元素會(huì)被跳過,不會(huì)被包含在新數(shù)組中。
// 索引為5的位置,沒有初始化值,不會(huì)被遍歷 let arr = [ 0, 1, 2, -3, 4,, 5 ] // 刪除掉最后一個(gè)元素 delete arr[6] // 過濾出大于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的位置,沒有初始化值,不會(huì)被遍歷 let arr = [ 0, 1, 2, -3, 4,, 5 ] // 刪除掉最后一個(gè)元素 delete arr[6] // 過濾出大于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è)例子來看一下他是怎么用的。
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)沒有傳遞初始值時(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
很類似,唯一不同的是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è)元素開始遍歷 let i = length - 1 // 如果沒有傳遞初始值,則取最后一個(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
二、查找類
1. find
基本使用:
find 方法返回?cái)?shù)組中滿足測(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: '前端胖頭魚' }) 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: '前端胖頭魚' }) console.log(index) // 4
2. findIndex
基本使用:
findIndex
方法返回?cái)?shù)組中滿足提供的測(cè)試函數(shù)的第一個(gè)元素的索引。若沒有找到對(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: '前端胖頭魚' }) console.log(index) // 3
3. indexOf
基本使用:
indexOf
方法返回在數(shù)組中可以找到一個(gè)給定元素的第一個(gè)索引,如果不存在,則返回-1。 mdn
arr.indexOf(searchElement[, fromIndex])
注意點(diǎn):
- 如果開始查找的索引值大于或等于數(shù)組長(zhǎng)度,意味著不會(huì)在數(shù)組里查找,返回-1
- 如果參數(shù)中提供的索引值是一個(gè)負(fù)值,則將其作為數(shù)組末尾的一個(gè)抵消,即-1表示從最后一個(gè)元素開始查找,-2表示從倒數(shù)第二個(gè)元素開始查找 ,以此類推
- 如果參數(shù)中提供的索引值是一個(gè)負(fù)值,并不改變其查找順序,查找順序仍然是從前向后查詢數(shù)組
- 如果抵消后的索引值仍小于0,則整個(gè)數(shù)組都將會(huì)被查詢。其默認(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)和基本你使用,聰明的你肯定一眼就知道怎么寫啦
Array.prototype.indexOf2 = function (targetEle, fromIndex) { const length = this.length fromIndex = +fromIndex || 0 // 數(shù)組為空或者從大于等于數(shù)組長(zhǎng)度的地方開始檢索,都直接是-1 if (length === 0 || fromIndex >= length) { return -1 } /* 1. 從fromIndex開始搜索元素 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
位置開始逆向查找。 - 如果
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-- } // 沒找到返回-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
方法用來判斷一個(gè)數(shù)組是否包含一個(gè)指定的值,如果包含則返回 true,否則返回false
。mdn
arr.includes(valueToFind[, fromIndex])
注意點(diǎn):
- 從fromIndex 索引處開始查找
valueToFind
。 - 如果為負(fù)值,則按升序從
array.length + fromIndex
的索引開始搜 - 數(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)度的地方開始檢索,都直接是-1 if (length === 0 || fromIndex >= length) { return false } /* 1. 從fromIndex開始搜索元素 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
三、增刪改類
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ù)組的開頭,并返回該數(shù)組的新長(zhǎng)度(該方法修改原有數(shù)組 ) 。
注意點(diǎn):
- 如果傳入多個(gè)參數(shù),它們會(huì)被以塊的形式插入到對(duì)象的開始位置,它們的順序和被作為參數(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è)元素開始,后面的元素都往前移動(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沒填的話,默認(rèn)是length,否則取填寫的 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ù)組本身展開一層 let newArray = [ ...this ] let i = 0 while (i < length) { const value = concatEles[ i ] // 對(duì)數(shù)組元素展開一層 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ù)組的所有元素通過字符標(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ù)量或類型。
注意點(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]
五、扁平類
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ì)平鋪展開一層 const arr2 = [0, 1, 2, [[[3, 4]]]] console.log(arr2.flat(2)) // [0, 1, 2, [3, 4]] 指定展開兩層
代碼實(shí)現(xiàn):
Array.prototype.flat2 = function (depth = 1) { const result = [] const flat = (arr, depth) => { for (let item of arr) { // 當(dāng)層數(shù)還未全部展開的時(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)文章希望大家以后多多支持腳本之家!
國慶將至,祝大家節(jié)日快樂,浪浪浪七天樂。
- 一篇文章帶你詳細(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ù)組過濾從簡(jiǎn)單到多條件篩選
- JavaScript數(shù)組reduce()方法的語法與實(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-07TypeScript?泛型推斷實(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