前言
各位朋友,JavaScript 中的数组一定是大家非常熟悉的,我们每天都会使用它的各种方法,比如 push
、pop
、forEach
、map
等等。
1. forEach
forEach
是我们工作中非常常用的数组方法,它的实现相对简单,是我们需要完成的第一个函数。
代码
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) {
// Deleted, the newly added element index i is not in the array, so it will not be accessed
if (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 out
demoArr.push(5)
} else if (i === 2) {
// 4 will not be printed out, but "4-4" will be printed out
demoArr.splice(3, 1, '4-4')
}
console.log(it)
})
哇,恭喜你!我们已经实现了 forEach
的功能。
2. map
你通常会用 map
做什么?大多数时候是将一个数组转换为另一个数组。
代码
Array.prototype.map2 = function (callback, thisCtx) {
if (typeof callback !== 'function') {
throw `${callback} is not a function`
}
const length = this.length
let i = 0
// The return value of the map method is a new array
let newArray = []
while (i < length) {
// Deleted and uninitialized values will not be accessed
if (this.hasOwnProperty(i)) {
newArray.push(callback.call(thisCtx, this[ i ], i, this))
}
i++
}
// Return new array
return 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]
3. every
every()
方法测试一个数组中的所有元素是否都通过了指定函数的测试。它返回一个布尔值。
every
方法有三个点可能是你之前没有注意到的,它们是什么?
- 在空数组上调用
every
方法将返回true
。 callback
方法仅在已分配值的索引上调用。- 如果值被删除,则不会调用
callback
。
let emptyArr = []
// Calling every method on an empty array returns true
console.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.length
let i = 0
// If the length of the array is 0, the while loop will not be entered
while (i < length) {
// False will be returned as long as a value does not conform to the judgment of callback
if (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 true
console.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.length
let i = 0
while (i < length) {
// Returns true if any element meets the callback condition
if (this.hasOwnProperty(i) && callback.call(thisCtx, this[ i ], i, this)) {
return true
}
i++
}
return false
}
测试
let emptyArr = []
// An empty array will return false
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()
方法创建一个新数组,其中包含通过所提供函数实现的测试的所有元素。
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 array
let newArray = []
let i = 0
while (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 value
let arr = [ 0, 1, 2, -3, 4,, 5 ]
// we try to remove the last element
delete arr[6]
// filter out values greater than 0
let 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
// initialization
prev = initialValue = 1, cur = 2
// step 1
prev = (1 + 2) = 3, cur = 3
// step 2
prev = (3 + 3) = 6, cur = 4
// step 3
prev = (6 + 4) = 10, cur = undefined (quit)
测试
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
// When the initial value is not passed, use the first value of the array as the initial value
if (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
7. reduceRight
reduceRight()
方法从右到左对数组中的每个值(包括降序数组)应用一个函数,以将其减少为单个值。
它与 reduce
非常相似,只是 reduceRight
是从右到左遍历的。
const sum = [1, 2, 3, 4].reduce((prev, cur) => {
console.log(prev, cur)
return prev + cur;
})
// 1 2
// 3 3
// 6 4
console.log(sum) // 10
const sum2 = [1, 2, 3, 4].reduceRight((prev, cur) => {
console.log(cur)
return prev + cur;
})
// 4 3
// 7 2
// 9 1
console.log(sum2) // 10
代码
Array.prototype.reduceRight2 = function (callback, initValue) {
if (typeof callback !== 'function') {
throw `${callback} is not a function`
}
let pre = initValue
const length = this.length
// Start with the last element
let i = length - 1
// If no initial value is passed, the last element is taken as the initial value
if (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 1
console.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.length
let i = 0
while (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 returned
if (callback.call(thisCtx, value, i, this)) {
return value
}
i++
}
// otherwise return undefined
return 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.length
let i = 0
while (i < length) {
// Return index i that conforms to callback logic
if (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
10. indexOf
indexOf()
方法返回在数组中可以找到给定元素的第一个索引,如果不存在,则返回-1。
arr.indexOf(searchElement[, fromIndex])
注意:
- 如果开始搜索的索引值大于或等于数组的长度,则表示不在数组中进行搜索,并返回 -1。
- 如果
fromIndex
是负数,则按照规则进行搜索:-1 表示从最后一个元素开始搜索,-2 表示从倒数第二个元素开始搜索,依此类推。 - 如果
fromIndex
是负数,则仍然从前向后搜索数组。
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
console.log(array.indexOf(2, -4)) // 0
代码
Array.prototype.indexOf2 = function (targetEle, fromIndex) {
const length = this.length
fromIndex = +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 -1
if (length === 0 || fromIndex >= length) {
return -1
}
/*
1. Search elements from fromIndex
2. Use it directly when fromindex is greater than 0
3. 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 targetEle
if (this.hasOwnProperty(i) && targetEle === this[ i ]) {
return i
}
i++
}
return -1
}
测试
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
console.log(array.indexOf2(2, -4)) // 0
11. lastIndexOf
lastIndexOf()
方法返回在数组中可以找到给定元素的最后一个索引,如果不存在,则返回-1。该数组从后向前搜索,从 fromIndex
处开始。
它与 indexOf
非常相似,只是 lastIndexOf
是从右到左遍历的。
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
代码
Array.prototype.lastIndexOf2 = function (targetEle, fromIndex) {
const length = this.length
fromIndex = 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 i
if (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 targetEle
if (i in this && targetEle === this[ i ]) {
return i
}
i--
}
// Returns -1 when the current value is not found
return -1
}
测试
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
12. includes
includes()
方法确定数组是否包含某个特定的值,返回 true 或 false。
arr.includes(valueToFind[, fromIndex])
注意:
includes
方法将从fromIndex
索引开始搜索valueToFind
。- 如果
fromIndex
是负数,则从array.length + fromIndex
开始搜索。 - 如果数组中存在
NaN
,则[..., NaN]
包含 (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
代码
Array.prototype.includes2 = function (targetEle, fromIndex) {
const length = this.length
fromIndex = +fromIndex || 0
if (length === 0 || fromIndex >= length) {
return false
}
// Search for elements from the position of fromIndex
let i = Math.max(fromIndex >= 0 ? fromIndex : length - Math.abs(fromIndex), 0)
while (i < length) {
const value = this[ i ]
// Please note NaN
if (targetEle === value || typeof targetEle === 'number' && typeof value === 'number' && isNaN(targetEle) && isNaN(value)) {
return true
}
i++
}
return false
}
测试
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
13. push
push() 方法将一个或多个元素添加到数组的末尾,并返回数组新的长度。
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
代码
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
}
测试
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
14. pop
pop() 方法从数组中删除最后一个元素,并返回该元素。该方法会改变数组的长度。
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 undefined
if (length === 0) {
return undefined
}
const delEle = this[ length - 1 ]
this.length = length - 1
return delEle
}
测试
let arr = [ 1, 2 ]
let arr2 = []
console.log(arr.pop2(), arr) // 2 [1]
console.log(arr2.pop2(), arr2) // undefined []
15. unshift
unshift() 方法将一个或多个元素添加到数组的开头,并返回数组新的长度。
注意
如果一次调用 unshift() 时传入多个参数,将得到与多次调用 unshift() 并传入一个参数不同的结果(例如循环调用)。
let arr = [4,5,6]
// Insert multiple elements at once
arr.unshift(1,2,3)
console.log(arr) // [1, 2, 3, 4, 5, 6]
let arr2 = [4,5,6]
// Insert multiple times
arr2.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 array
let newArray = [ ...unshiftEles, ...this ]
let length = newArray.length
let i = 0
if (unshiftEles.length === 0) {
return length
}
// Recopy to array
while (i < length) {
this[ i ] = newArray[ i ]
i++
}
return this.length
}
测试
let arr = [4,5,6]
// Insert multiple elements at once
arr.unshift2(1,2,3)
console.log(arr) // [1, 2, 3, 4, 5, 6]
let arr2 = [4,5,6]
// Insert multiple times
arr2.unshift2(1)
arr2.unshift2(2)
arr2.unshift2(3)
console.log(arr2); // [3, 2, 1, 4, 5, 6]
16. shift
shift() 方法从数组中删除第一个元素,并返回该元素。该方法会改变数组的长度。
let arr = [ 1, 2 ]
console.log(arr.shift(), arr) // 1 [2]
console.log(arr.shift(), arr) // 2 []
代码
Array.prototype.shift2 = function () {
const length = this.length
const delValue = this[ 0 ]
let i = 1
while (i < length) {
// Starting from the first element, the following elements move forward one bit
this[ i - 1 ] = this[ i ]
i++
}
// Set the length of the array
this.length = length - 1
// Return deleted value
return delValue
}
测试
let arr = [ 1, 2 ]
console.log(arr.shift2(), arr) // 1 [2]
console.log(arr.shift2(), arr) // 2 []
17. reverse
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 = 0
let j = this.length - 1
while (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
fill() 方法将数组中的所有元素更改为静态值,从开始索引(默认为0)到结束索引(默认为数组长度)。它返回修改后的数组。
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.length
start = start >> 0
// The default value of end is length
end = typeof end === 'undefined' ? length : end >> 0
// The minimum value of start is 0 and the maximum value is length
start = start >= 0 ? Math.min(start, length) : Math.max(start + length, 0)
// The minimum value of end is 0 and the maximum value is length
end = end >= 0 ? Math.min(end, length) : Math.max(end + length, 0)
// The element that fills the specified range is value
while (start < end) {
this[ start ] = value
start++
}
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]
19. concat
concat() 方法用于合并两个或多个数组。该方法不会改变现有数组,而是返回一个新数组。
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 layer
let newArray = [ ...this ]
let i = 0
while (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]]
20. join
join() 方法通过使用逗号或指定的分隔符字符串将数组(或类似数组对象)中的所有元素连接到一起,创建并返回一个新字符串。如果数组只有一个项,则该项将在不使用分隔符的情况下返回。
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
代码
Array.prototype.join2 = function (format = ',') {
const length = this.length
// Save the last element because it does not participate in the connection of format
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
}
测试
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
评论(0)