你知道这20个数组方法是怎么实现的吗?

英文 | https://javascript.plainenglish.io/20-javascript-array-methods-every-developer-should-know-6c04cc7a557d
翻译 | 杨小爱
Array.prototype.forEach2 = function (callback, thisCtx) {if (typeof callback !== 'function') {throw `${callback} is not a function`}const length = this.lengthlet i = 0while (i < length) {// Deleted, the newly added element index i is not in the array, so it will not be accessedif (this.hasOwnProperty(i)) {callback.call(thisCtx, this[ i ], i, this)}i++}}
let demoArr = [ 1, 2, 3, 4, , 5 ]demoArr.forEach2((it, i) => {if (i === 1) {// 5 will not be printed outdemoArr.push(5)} else if (i === 2) {// 4 will not be printed out, but "4-4" will be printed outdemoArr.splice(3, 1, '4-4')}console.log(it)})/*1234-45*/
Array.prototype.map2 = function (callback, thisCtx) {if (typeof callback !== 'function') {throw `${callback} is not a function`}const length = this.lengthlet i = 0// The return value of the map method is a new arraylet newArray = []while (i < length) {// Deleted and uninitialized values will not be accessedif (this.hasOwnProperty(i)) {newArray.push(callback.call(thisCtx, this[ i ], i, this))}i++}// Return new arrayreturn newArray}
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: 'fatfish' })console.log(arr2) // [0, 1, 4, 9, 16, 25]
在空数组上调用 every 方法将返回 true。 回调方法只会被已经赋值的索引调用。 如果值被删除,回调将不会被调用
let emptyArr = []// Calling every method on an empty array returns trueconsole.log(emptyArr.every((it) => it > 0)) // true// The `callback` method will only be called by an index that has already been assigned a value.let arr = [ 0, 1, 2, 3, 4,, 5, -1 ]// The `callback` method will not be called when an array value is deleted or an index that has never been assigned a value.delete arr[7]console.log(arr.every((it) => it >= 0)) // true
代码
Array.prototype.every2 = function (callback, thisCtx) {if (typeof callback !== 'function') {throw `${callback} is not a function`}const length = this.lengthlet i = 0// If the length of the array is 0, the while loop will not be enteredwhile (i < length) {// False will be returned as long as a value does not conform to the judgment of callbackif (this.hasOwnProperty(i) && !callback.call(thisCtx, this[ i ], i, this)) {return false}i++}return true}
let emptyArr = []// Calling every method on an empty array returns trueconsole.log(emptyArr.every2((it) => it > 0)) // true// The `callback` method will only be called by an index that has already been assigned a value.let arr = [ 0, 1, 2, 3, 4,, 5, -1 ]// The `callback` method will not be called when an array value is deleted or an index that has never been assigned a value.delete arr[7]console.log(arr.every2((it) => it >= 0)) // true
4、some
some() 方法测试数组中的至少一个元素是否通过了提供的函数实现的测试。
代码
Array.prototype.some2 = function (callback, thisCtx) {if (typeof callback !== 'function') {throw `${callback} is not a function`}const length = this.lengthlet i = 0while (i < length) {// Returns true if any element meets the callback conditionif (this.hasOwnProperty(i) && callback.call(thisCtx, this[ i ], i, this)) {return true}i++}return false}
let emptyArr = []// An empty array will return falseconsole.log(emptyArr.some2((it) => it > 0)) // falselet arr = [ 0, 1, 2, 3, 4,, 5, -1 ]delete arr[7]console.log(arr.some2((it) => it < 0)) // falseconsole.log(arr.some2((it) => it > 0)) // true
5、filter
filter() 方法创建一个新数组,其中包含所有通过所提供函数实现的测试的元素。
Array.prototype.filter2 = function (callback, thisCtx) {if (typeof callback !== 'function') {throw `${callback} is not a function`}const length = this.length// The return value will be a new arraylet newArray = []let i = 0while (i < length) {if (this.hasOwnProperty(i) && callback.call(thisCtx, this[ i ], i, this)) {newArray.push(this[ i ])}i++}return newArray}
// The position with index 5 will not be traversed because it has no initialization valuelet arr = [ 0, 1, 2, -3, 4,, 5 ]// we try to remove the last elementdelete arr[6]// filter out values greater than 0let filterArr = arr.filter2((it) => it > 0)console.log(filterArr) // [ 1, 2, 4 ]
6、reduce
这个函数稍微复杂一些。让我们用一个例子来看看它是如何使用的。
const sum = [1, 2, 3, 4].reduce((prev, cur) => {return prev + cur;})console.log(sum) // 10// initializationprev = initialValue = 1, cur = 2// step 1prev = (1 + 2) = 3, cur = 3// step 2prev = (3 + 3) = 6, cur = 4// step 3prev = (6 + 4) = 10, cur = undefined (quit)
代码
Array.prototype.reduce2 = function (callback, initValue) {if (typeof callback !== 'function') {throw `${callback} is not a function`}let pre = initValuelet i = 0const length = this.length// When the initial value is not passed, use the first value of the array as the initial valueif (typeof pre === 'undefined') {pre = this[0]i = 1}while (i < length) {if (this.hasOwnProperty(i)) {pre = callback(pre, this[ i ], i, this)}i++}return pre}
const sum = [1, 2, 3, 4].reduce2((prev, cur) => {return prev + cur;})console.log(sum) // 10
const sum = [1, 2, 3, 4].reduce((prev, cur) => {console.log(prev, cur)return prev + cur;})// 1 2// 3 3// 6 4console.log(sum) // 10const sum2 = [1, 2, 3, 4].reduceRight((prev, cur) => {console.log(cur)return prev + cur;})// 4 3// 7 2// 9 1console.log(sum2) // 10
代码
Array.prototype.reduceRight2 = function (callback, initValue) {if (typeof callback !== 'function') {throw `${callback} is not a function`}let pre = initValueconst length = this.length// Start with the last elementlet i = length - 1// If no initial value is passed, the last element is taken as the initial valueif (typeof pre === 'undefined') {pre = this[i]i--}while (i >= 0) {if (this.hasOwnProperty(i)) {pre = callback(pre, this[ i ], i, this)}i--}return pre}
测试一下
const sum = [1, 2, 3, 4].reduceRight2((prev, cur) => {console.log(cur)return prev + cur;})// 4 3// 7 2// 9 1console.log(sum) // 10
8、find
find() 方法返回提供的数组中满足提供的测试功能的第一个元素。如果没有值满足测试函数,则返回 undefined。
代码
Array.prototype.find2 = function (callback, thisCtx) {if (typeof callback !== 'function') {throw `${callback} is not a function`}const length = this.lengthlet i = 0while (i < length) {const value = this[ i ]// As long as there is an element that matches the logic of the callback function, the element value is returnedif (callback.call(thisCtx, value, i, this)) {return value}i++}// otherwise return undefinedreturn undefined}
let arr = [ 0, 1, 2, 3, 4,, 5 ]let ele = arr.find2(function (it, i, array) {console.log(it, i, array, this)return it > 3}, { name: 'fatfish' })console.log(ele) // 4
9、findIndex
findIndex() 方法返回数组中满足提供的测试函数的第一个元素的索引。否则,它返回 -1,表示没有元素通过测试。
let arr = [ 0, 1, 2, 3, 4,, 5 ]let index = arr.findIndex((it, i, array) => {return it > 2})console.log(index) // 3
Array.prototype.findIndex2 = function (callback, thisCtx) {if (typeof callback !== 'function') {throw `${callback} is not a function`}const length = this.lengthlet i = 0while (i < length) {// Return index i that conforms to callback logicif (callback.call(thisCtx, this[ i ], i, this)) {return i}i++}return -1}
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: 'fatfish' })console.log(index) // 3
const array = [2, 5, 9]console.log(array.indexOf(2)) // 0console.log(array.indexOf(7)) // -1console.log(array.indexOf(9, 2)) // 2console.log(array.indexOf(2, -1)) // -1console.log(array.indexOf(2, -3)) // 0console.log(array.indexOf(2, -4)) // 0
代码
Array.prototype.indexOf2 = function (targetEle, fromIndex) {const length = this.lengthfromIndex = +fromIndex || 0// If the array is empty or the search starts from a place greater than or equal to the length of the array, it will directly return -1if (length === 0 || fromIndex >= length) {return -1}/*1. Search elements from fromIndex2. Use it directly when fromindex is greater than 03. If it is less than 0, first subtract the absolute value of fromIndex from the length. If it is still less than 0, take 0 directly*/let i = Math.max(fromIndex >= 0 ? fromIndex : length - Math.abs(fromIndex), 0)while (i < length) {// element in the array and equal to targetEleif (this.hasOwnProperty(i) && targetEle === this[ i ]) {return i}i++}return -1}
测试一下
const array = [2, 5, 9]console.log(array.indexOf2(2)) // 0console.log(array.indexOf2(7)) // -1console.log(array.indexOf2(9, 2)) // 2console.log(array.indexOf2(2, -1)) // -1console.log(array.indexOf2(2, -3)) // 0console.log(array.indexOf2(2, -4)) // 0
let array = [2, 5, 9, 2]console.log(array.lastIndexOf(2)) // 3console.log(array.lastIndexOf(7)) // -1console.log(array.lastIndexOf(2, 3)) // 3console.log(array.lastIndexOf(2, 2)) // 0console.log(array.lastIndexOf(2, -2)) // 0console.log(array.lastIndexOf(2, -1)) // 3
Array.prototype.lastIndexOf2 = function (targetEle, fromIndex) {const length = this.lengthfromIndex = typeof fromIndex === 'undefined' ? length - 1 : fromIndex// // Empty array, when fromIndex is negative and the absolute value is greater than the length of the array, the method returns -1, that is, the array will not be searched.if (length === 0 || fromIndex < 0 && Math.abs(fromIndex) >= length) {return -1}let iif (fromIndex >= 0) {// If `fromIndex` is greater than or equal to the length of the array, the entire array is searched.i = Math.min(fromIndex, length - 1)} else {i = length - Math.abs(fromIndex)}while (i >= 0) {// Returns the index when it is equal to targetEleif (i in this && targetEle === this[ i ]) {return i}i--}// Returns -1 when the current value is not foundreturn -1}
let array = [2, 5, 9, 2]console.log(array.lastIndexOf2(2)) // 3console.log(array.lastIndexOf2(7)) // -1console.log(array.lastIndexOf2(2, 3)) // 3console.log(array.lastIndexOf2(2, 2)) // 0console.log(array.lastIndexOf2(2, -2)) // 0console.log(array.lastIndexOf2(2, -1)) // 3
12、includes
includes() 方法确定数组是否在其条目中包含某个值,根据需要返回 true 或 false。
arr.includes(valueToFind[, fromIndex])console.log([1, 2, 3].includes(2)) // trueconsole.log([1, 2, 3].includes(4)) // falseconsole.log([1, 2, 3].includes(3, 3)) // falseconsole.log([1, 2, 3].includes(3, -1)) // trueconsole.log([1, 2, NaN].includes(NaN)) // true
代码
Array.prototype.includes2 = function (targetEle, fromIndex) {const length = this.lengthfromIndex = +fromIndex || 0if (length === 0 || fromIndex >= length) {return false}// Search for elements from the position of fromIndexlet i = Math.max(fromIndex >= 0 ? fromIndex : length - Math.abs(fromIndex), 0)while (i < length) {const value = this[ i ]// Please note NaNif (targetEle === value || typeof targetEle === 'number' && typeof value === 'number' && isNaN(targetEle) && isNaN(value)) {return true}i++}return false}
console.log([1, 2, 3].includes2(2)) // trueconsole.log([1, 2, 3].includes2(4)) // falseconsole.log([1, 2, 3].includes2(3, 3)) // falseconsole.log([1, 2, 3].includes2(3, -1)) // trueconsole.log([1, 2, NaN].includes2(NaN)) // true
const animals = ['pigs', 'goats', 'sheep']animals.push('cows')console.log(animals, animals.length)// ["pigs", "goats", "sheep", "cows"], 4animals.push('chickens', 'cats', 'dogs')console.log(animals, animals.length)// ["pigs", "goats", "sheep", "cows", "chickens", "cats", "dogs"], 7
Array.prototype.push2 = function (...pushEles) {const pushEleLength = pushEles.lengthconst length = this.lengthlet i = 0while (i < pushEleLength) {this[ length + i ] = pushEles[ i ]i++}return this.length}
测试一下
const animals = ['pigs', 'goats', 'sheep']animals.push2('cows')console.log(animals, animals.length)// ["pigs", "goats", "sheep", "cows"], 4animals.push2('chickens', 'cats', 'dogs')console.log(animals, animals.length)// ["pigs", "goats", "sheep", "cows", "chickens", "cats", "dogs"], 7
let arr = [ 1, 2 ]let arr2 = []console.log(arr.pop(), arr) // 2 [1]console.log(arr2.pop(), arr2) // undefined []
Array.prototype.pop2 = function () {const length = this.length// If it is an empty array, return undefinedif (length === 0) {return undefined}const delEle = this[ length - 1 ]this.length = length - 1return delEle}
let arr = [ 1, 2 ]let arr2 = []console.log(arr.pop2(), arr) // 2 [1]console.log(arr2.pop2(), arr2) // undefined []
let arr = [4,5,6]// Insert multiple elements at oncearr.unshift(1,2,3)console.log(arr) // [1, 2, 3, 4, 5, 6]let arr2 = [4,5,6]// Insert multiple timesarr2.unshift(1)arr2.unshift(2)arr2.unshift(3)console.log(arr2); // [3, 2, 1, 4, 5, 6]
Array.prototype.unshift2 = function (...unshiftEles) {// With "...", Insert the element to be added in front of the arraylet newArray = [ ...unshiftEles, ...this ]let length = newArray.lengthlet i = 0if (unshiftEles.length === 0) {return length}// Recopy to arraywhile (i < length) {this[ i ] = newArray[ i ]i++}return this.length}
let arr = [4,5,6]// Insert multiple elements at oncearr.unshift2(1,2,3)console.log(arr) // [1, 2, 3, 4, 5, 6]let arr2 = [4,5,6]// Insert multiple timesarr2.unshift2(1)arr2.unshift2(2)arr2.unshift2(3)console.log(arr2); // [3, 2, 1, 4, 5, 6]
let arr = [ 1, 2 ]console.log(arr.shift(), arr) // 1 [2]console.log(arr.shift(), arr) // 2 []
代码
Array.prototype.shift2 = function () {const length = this.lengthconst delValue = this[ 0 ]let i = 1while (i < length) {// Starting from the first element, the following elements move forward one bitthis[ i - 1 ] = this[ i ]i++}// Set the length of the arraythis.length = length - 1// Return deleted valuereturn delValue}
let arr = [ 1, 2 ]console.log(arr.shift2(), arr) // 1 [2]console.log(arr.shift2(), arr) // 2 []
17、reverse
(来自 MDN) reverse() 方法将数组反转到位。第一个数组元素成为最后一个,最后一个数组元素成为第一个。
const arr = [1, 2, 3]console.log(arr) // [1, 2, 3]arr.reverse()console.log(arr) // [3, 2, 1]
Array.prototype.reverse2 = function () {let i = 0let j = this.length - 1while (i < j) {[ this[ i ], this[ j ] ] = [ this[ j ], this[ i ] ]i++j--}return this}
const arr = [1, 2, 3]console.log(arr) // [1, 2, 3]arr.reverse2()console.log(arr) // [3, 2, 1]
18、fill
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]
Array.prototype.fill2 = function (value, start, end) {const length = this.lengthstart = start >> 0// The default value of end is lengthend = typeof end === 'undefined' ? length : end >> 0// The minimum value of start is 0 and the maximum value is lengthstart = start >= 0 ? Math.min(start, length) : Math.max(start + length, 0)// The minimum value of end is 0 and the maximum value is lengthend = end >= 0 ? Math.min(end, length) : Math.max(end + length, 0)// The element that fills the specified range is valuewhile (start < end) {this[ start ] = valuestart++}return this}
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]
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]]
代码
Array.prototype.concat2 = function (...concatEles) {const length = concatEles.length// The array itself needs to be expanded one layerlet newArray = [ ...this ]let i = 0while (i < length) {const value = concatEles[ i ]Array.isArray(value) ? newArray.push(...value) : newArray.push(value)i++}return newArray}
测试一下
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]]
const elements = ['Fire', 'Air', 'Water']const elements2 = ['Fire']console.log(elements.join()) // Fire,Air,Waterconsole.log(elements.join('')) // FireAirWaterconsole.log(elements.join('-')) // Fire-Air-Waterconsole.log(elements2.join('-')) // Fire
代码
Array.prototype.join2 = function (format = ',') {const length = this.length// Save the last element because it does not participate in the connection of formatlet 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}
测试一下
const elements = ['Fire', 'Air', 'Water']const elements2 = ['Fire']console.log(elements.join2()) // Fire,Air,Waterconsole.log(elements.join2('')) // FireAirWaterconsole.log(elements.join2('-')) // Fire-Air-Waterconsole.log(elements2.join2('-')) // Fire
学习更多技能
请点击下方公众号
![]()

评论
