前言
数组是咱们日常工作中用的最频繁的一类数据结构,能帮忙咱们解决许多问题,而其自身也蕴含靠近33个之多的办法,做了一个脑图分类如下,纯熟应用数组的你,是否想晓得他们外部的实现原理呢?
这篇文章会和你一起探索24+原生数组办法的外部实现,置信你看完肯定会有属于本人不一样的播种。
遍历类
1. forEach
根本应用
forEach
一个日常用的十分多的遍历函数,你肯定相熟到不能再相熟啦!这里咱们着重看一些比拟重要且容易疏忽的点。mdn
- 该办法对数组的每个元素执行一次给定的函数,返回值是
undefiend
。 - 该办法按升序为数组中含有效值的每一项执行一次
callback
函数,未初始化的项将被跳过(例如在稠密数组上)。 - 如果曾经存在的值被扭转,则传递给
callback
的值是forEach()
遍历到他们那一刻的值。 - 已删除的项不会被遍历到
举个小例子
let demoArr = [ 1, 2, 3, 4, , 5 ]demoArr.forEach((it, i) => { if (i === 1) { // 后增加进去的不会被拜访到 demoArr.push(5) } else if (i === 2) { // 4将不会被拜访到,而4-4会被拜访到 demoArr.splice(3, 1, '4-4') } console.log(it)})/* 1 2 3 4-4 5*/
代码实现
点击查看源码实现
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不在数组内,所以不会被拜访到 if (i in this) { callback.call(thisCtx, this[ i ], i, this) } i++ }}
同样用方才的例子,改下后的输入是一样的
测试一把
// 测试let demoArr = [ 1, 2, 3, 4, , 5 ]demoArr.forEach2((it, i) => { if (i === 1) { // 后增加进去的不会被拜访到 demoArr.push(5) } else if (i === 2) { // 4将不会被拜访到,相仿4-4会被拜访到 demoArr.splice(3, 1, '4-4') } console.log(it)})/* 1 2 3 4-4 5*/
2. map
根本应用
map
办法创立一个新数组,其后果是该数组中的每个元素是调用一次提供的函数后的返回值。mdn
留神点
callback
函数只会在有值的索引上被调用- 素来没被赋过值或者应用
delete
删除的索引则不会被调用。
// 留神索引为2的地位没有赋值let arr = [ 1, 2, ,4, 5 ]// 删除索引3delete arr[3]console.log(arr.map((it) => it * it))// [ 1, 4, 25 ]
代码实现
点击查看源码实现
Array.prototype.map2 = function (callback, thisCtx) { if (typeof callback !== 'function') { throw `${callback} is not a function` } const length = this.length let i = 0 // map返回值是一个新的数组 let newArray = [] while (i < length) { // 被删除的,未初始化的都不会被遍历到 if (i in this) { newArray.push(callback.call(thisCtx, this[ i ], i, this)) } i++ } // 返回新的数组 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: '前端胖头鱼' })console.log(arr2)
3. every
根本应用
every
办法测试一个数组内的所有元素是否都能通过某个指定函数的测试。它返回一个布尔值。mdn
留神点
- 若收到一个空数组,此办法在所有状况下都会返回
true
。 callback
只会为那些曾经被赋值的索引调用- 不会为那些被删除或从未被赋值的索引调用
// 举例let emptyArr = []// 空数组间接返回trueconsole.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
代码实现
点击查看源码实现
Array.prototype.every2 = function (callback, thisCtx) { if (typeof callback !== 'function') { throw `${callback} is not a function` } const length = this.length let i = 0 // 空函数不会走进循环 while (i < length) { // 只有有一个值不合乎callback预期就返回false if (i in this && !callback.call(thisCtx, this[ i ], i, this)) { return false } i++ } return true}
测试一把
还是拿例子做测试
let emptyArr = []console.log(emptyArr.every2((it) => it > 0)) // truelet arr = [ 0, 1, 2, 3, 4,, 5, -1 ]delete arr[7]console.log(arr.every2((it) => it >= 0)) // true
4. some
根本应用
some
办法测试数组中是不是至多有1个元素通过了被提供的函数测试。它返回的是一个Boolean类型的值。 mdn
留神点
callback
只会在那些”有值“的索引上被调用,不会在那些被删除或从来未被赋值的索引上调用。
举个例子
let emptyArr = []// 空数组间接返回falseconsole.log(emptyArr.some((it) => it > 0)) // falselet arr = [ 0, 1, 2, 3, 4,, 5, -1 ]// 还没有遍历前把-1删除了,惟一小于0的值不存在了,即返回falsedelete arr[7]console.log(arr.some((it) => it < 0)) // false
代码实现
点击查看源码实现
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) { // 只有有一个元素合乎callback条件,就返回true if (i in this && callback.call(thisCtx, this[ i ], i, this)) { return true } i++ } return false}
测试一把
let emptyArr = []// 空数组间接返回trueconsole.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
办法创立一个新数组, 其蕴含通过所提供函数测试的所有元素。 mdn
留神点
filter
为数组中的每个元素调用一次callback
函数,并利用所有使得callback
返回 true 或等价于 true 的值的元素创立一个新数组。callback
只会在曾经赋值的索引上被调用,对于那些曾经被删除或者从未被赋值的索引不会被调用。- 那些没有通过
callback
测试的元素会被跳过,不会被蕴含在新数组中。
// 索引为5的地位,没有初始化值,不会被遍历let arr = [ 0, 1, 2, -3, 4,, 5 ]// 删除掉最初一个元素delete arr[6]// 过滤出大于0的值let filterArr = arr.filter((it) => it > 0)console.log(filterArr) // [ 1, 2, 4 ]
代码实现
点击查看源码实现
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}
测试
// 索引为5的地位,没有初始化值,不会被遍历let arr = [ 0, 1, 2, -3, 4,, 5 ]// 删除掉最初一个元素delete arr[6]// 过滤出大于0的值let filterArr = arr.filter2((it) => it > 0)console.log(filterArr) // [ 1, 2, 4 ]
6. reduce
根本应用
reduce
办法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其后果汇总为单个返回值 mdn
这个函数略微简单一些,咱们用一个例子来看一下他是怎么用的。
const sum = [1, 2, 3, 4].reduce((prev, cur) => { return prev + cur;})console.log(sum) // 10// 初始设置prev = initialValue = 1, cur = 2// 第一次迭代prev = (1 + 2) = 3, cur = 3// 第二次迭代prev = (3 + 3) = 6, cur = 4// 第三次迭代prev = (6 + 4) = 10, cur = undefined (退出)
代码实现
点击查看源码实现
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 // 当没有传递初始值时,取第一个作为初始值 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}
测试一把
const sum = [1, 2, 3, 4].reduce2((prev, cur) => { return prev + cur;})console.log(sum) // 10
7. reduceRight
根本应用
reduceRight
办法对数组中的每个元素执行一个由您提供的reducer函数(降序执行),将其后果汇总为单个返回值 mdn
和reduce很相似,惟一不同的是reduceRight
从右往左遍历
const sum = [1, 2, 3, 4].reduce((prev, cur) => { console.log(cur) return prev + cur;})// 2 1// 3 2// 4 3console.log(sum) // 10const sum2 = [1, 2, 3, 4].reduceRight((prev, cur) => { console.log(cur) return prev + cur;})// 3 2 // 2 1// 1 0console.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 // 从最初一个元素开始遍历 let i = length - 1 // 如果没有传递初始值,则取最初一个作为初始值 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}
测试一把
const sum = [1, 2, 3, 4].reduceRight2((prev, cur) => { console.log(cur) return prev + cur;})// 3 2// 2 1// 1 0console.log(sum) // 10
查找类
8. find
根本应用
find
办法返回数组中满足测试函数的第一个元素的值。否则返回undefined
, mdn
留神点
find
办法对数组中的每一项元素执行一次callback
函数,直至有一个 callback 返回true
- 当找到了这样一个元素后,该办法会立刻返回这个元素的值,否则返回
undefined
callback
函数会为数组中的每个索引调用即从0
到length - 1
,而不仅仅是那些被赋值的索引。(这个点是和后面几个函数不一样的中央)
let arr = [ 0, 1, 2, 3, 4,, 5 ]let index = arr.find((it) => { return it > 3}, { name: '前端胖头鱼' })console.log(index) // 4
代码实现
点击查看源码实现
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 ] // 只有有一个元素合乎callback回调函数的逻辑,就返回元素value if (callback.call(thisCtx, value, i, this)) { return value } i++ } // 否则返回undefined return undefined}
测试一把
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
9. findIndex
根本应用
findIndex
办法返回数组中满足提供的测试函数的第一个元素的索引。若没有找到对应元素则返回-1。 mdn
和find函数不同的中央在于,findIndex是返回索引而非值, 留神点也和find根本一样
findIndex
办法对数组中的每个数组索引0 ~ length-1
(包含)执行一次callback
函数,直到找到一个callback
函数返回true的值。- 如果找到这样的元素,
findIndex
会立刻返回该元素的索引。如果回调从不返回真值,或者数组的length
为0,则findIndex
返回-1 - 与某些其余数组办法(如Array#some)不同,在稠密数组中,即便对于数组中不存在的条目标索引也会调用回调函数
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) { // 合乎callback逻辑的间接返回索引i if (callback.call(thisCtx, this[ i ], i, this)) { return i } i++ } // 否则返回-1 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: '前端胖头鱼' })console.log(index) // 3
10. indexOf
根本应用
indexOf
办法返回在数组中能够找到一个给定元素的第一个索引,如果不存在,则返回-1。 mdn
arr.indexOf(searchElement[, fromIndex])
留神点
- 如果开始查找的索引值大于或等于数组长度,意味着不会在数组里查找,返回-1
- 如果参数中提供的索引值是一个负值,则将其作为数组开端的一个对消,即-1示意从最初一个元素开始查找,-2示意从倒数第二个元素开始查找 ,以此类推
- 如果参数中提供的索引值是一个负值,并不扭转其查找程序,查找程序依然是从前向后查问数组
- 如果对消后的索引值仍小于0,则整个数组都将会被查问。其默认值为0.
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)) // 0
代码实现
点击查看源码实现
有了下面的留神点和根本你应用,聪慧的你必定一眼就晓得怎么写啦
Array.prototype.indexOf2 = function (targetEle, fromIndex) { const length = this.length fromIndex = +fromIndex || 0 // 数组为空或者从大于等于数组长度的中央开始检索,都间接是-1 if (length === 0 || fromIndex >= length) { return -1 } /* 1. 从fromIndex开始搜寻元素 2. fromIndex大于0时候间接取即可 3. 小于0先用长度减去fromIndex的绝对值,如果还是小于0,就间接取0即可 */ let i = Math.max(fromIndex >= 0 ? fromIndex : length - Math.abs(fromIndex), 0) while (i < length) { // 在数组内的元素并且和targetEle强等 if (i in this && 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)) // 0
11. lastIndexOf
根本应用
lastIndexOf
办法返回指定元素在数组中的最初一个的索引,如果不存在则返回 -1。 mdn
arr.lastIndexOf(searchElement[, fromIndex])
留神点
- 从
arr.length - 1
地位开始逆向查找。 - 如果
fromIndex
大于或等于数组的长度,则整个数组会被查找。 - 如果
fromIndex
为负值,将其视为从数组开端向前的偏移。即便该值为负,数组依然会被从后向前查找。 - 如果
fromIndex
值为负时,其绝对值大于数组长度,则办法返回 -1,即数组不会被查找。
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.length fromIndex = typeof fromIndex === 'undefined' ? length - 1 : fromIndex // 数组为空,以及该值为负时且绝对值大于数组长度,则办法返回 -1,即数组不会被查找。 if (length === 0 || fromIndex < 0 && Math.abs(fromIndex) >= length) { return -1 } let i if (fromIndex >= 0) { // 如果`fromIndex`大于或等于数组的长度,则整个数组会被查找。 // 也就是当大于数组length - 1时,会取length - 1 i = Math.min(fromIndex, length - 1) } else { i = length - Math.abs(fromIndex) } while (i >= 0) { // 等于targetEle时返回索引 if (i in this && targetEle === this[ i ]) { return i } // 逆向遍历 i-- } // 没找到返回-1 return -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。mdn
arr.includes(valueToFind[, fromIndex])
留神点
- 从
fromIndex
索引处开始查找valueToFind
。 - 如果为负值,则按升序从
array.length + fromIndex
的索引开始搜 - 数组中存在NaN的话,
[ ..., NaN ].includes(NaN)为true
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.length fromIndex = +fromIndex || 0 // 数组为空或者从大于等于数组长度的中央开始检索,都间接是-1 if (length === 0 || fromIndex >= length) { return false } /* 1. 从fromIndex开始搜寻元素 2. fromIndex大于0时候间接取即可 3. 小于0先用长度减去fromIndex的绝对值,如果还是小于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}
测试一把
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
增删改类
13. push
根本应用
push
办法将一个或多个元素增加到数组的开端,并返回该数组的新长度。mdn
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.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"], 4animals.push2('chickens', 'cats', 'dogs')console.log(animals, animals.length) // ["pigs", "goats", "sheep", "cows", "chickens", "cats", "dogs"], 7
14. pop
根本应用
pop
办法从数组中删除最初一个元素,并返回该元素的值。此办法更改数组的长度。mdn
let arr = [ 1, 2 ]let arr2 = []console.log(arr.pop(), arr) // 2 [1]console.log(arr2.pop(), arr2) // undefined []
代码实现和应用一样简略,只有把数组的最初一个元素返回,并且让数组长度减1即可
代码实现
点击查看源码实现
Array.prototype.pop2 = function () { const length = this.length // 空数组上pop,间接返回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]// 一次性插入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]
代码实现
点击查看源码实现
Array.prototype.unshift2 = function (...unshiftEles) { // 借助扩大符,将须要增加的元素以块的模式插入到数组后面 let newArray = [ ...unshiftEles, ...this ] let length = newArray.length let i = 0 if (unshiftEles.length === 0) { return length } // 从新复制给数组 while (i < length) { this[ i ] = newArray[ i ] i++ } return this.length}
测试一把
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]
16. shift
根本应用
shift
办法从数组中删除第一个元素,并返回该元素的值。 mdn
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) { // 从第一个元素开始,前面的元素都往前挪动一位 this[ i - 1 ] = this[ i ] i++ } // 设置好数组的长度 this.length = length - 1 // 返回删除的值 return delValue}
测试一把
let arr = [ 1, 2 ]console.log(arr.shift2(), arr) // 1 [2]console.log(arr.shift2(), arr) // 2 []
17. reverse
根本应用
reverse
办法将数组中元素的地位颠倒,并返回该数组。即数组的第一个元素会变成最初一个,数组的最初一个元素变成第一个。mdn
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
办法用一个固定值填充一个数组中从起始索引到终止索引内的全副元素。不包含终止索引。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]
代码实现
点击查看源码实现
Array.prototype.fill2 = function (value, start, end) { const length = this.length start = start >> 0 // end没填的话,默认是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++ } // 返回被批改的数组 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
办法用于合并两个或多个数组。此办法不会更改现有数组,而是返回一个新数组 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]]
代码实现
点击查看源码实现
Array.prototype.concat2 = function (...concatEles) { const length = concatEles.length // 数组自身开展一层 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,Waterconsole.log(elements.join('')) // FireAirWaterconsole.log(elements.join('-')) // Fire-Air-Waterconsole.log(elements2.join('-')) // Fire
代码实现
点击查看源码实现
Array.prototype.join2 = function (format = ',') { const length = this.length // 保留最初一个元素,因为他不参加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,Waterconsole.log(elements.join2('')) // FireAirWaterconsole.log(elements.join2('-')) // Fire-Air-Waterconsole.log(elements2.join2('-')) // Fire
静态方法
21. Array.isArray
根本应用
Array.isArray() 用于确定传递的值是否是一个 Array
。
Array.isArray([1, 2, 3]) // trueArray.isArray({foo: 123}) // falseArray.isArray("foobar") // falseArray.isArray(undefined) // false
代码实现
点击查看源码实现
这个非常简单,只须要一句话就能够
Array.isArray2 = function (ele) { return Object.prototype.toString.call(ele) === '[object Array]';}
测试一把
Array.isArray2([1, 2, 3]) // trueArray.isArray2({foo: 123}) // falseArray.isArray2("foobar") // falseArray.isArray2(undefined) // false
22. Array.of
根本应用
Array.of
办法创立一个具备可变数量参数的新数组实例,而不思考参数的数量或类型。
留神点
Array.of()
和 Array
构造函数之间的区别在于解决整数参数:
Array.of(7)
创立一个具备单个元素 7 的数组,而 Array(7)
创立一个长度为7的空数组(留神: 这是指一个有7个空位(empty)的数组,而不是由7个undefined
组成的数组)
Array.of(7); // [7]Array.of(1, 2, 3); // [1, 2, 3]Array(7); // [ , , , , , , ]Array(1, 2, 3); // [1, 2, 3]
代码实现
点击查看源码实现
实现思路就是把你穿进去的值,挨个赋值到以后数组即可
Array.of2 = function (...eles) { const length = eles.length let i = 0 let newArray = [] while (i < length) { newArray[ i ] = eles[ i ] i++ } return newArray}
测试一把
Array.of2(7); // [7]Array.of2(1, 2, 3); // [1, 2, 3]
扁平类
23. flat
根本应用
flat()
办法会依照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。 mdn
const arr1 = [0, 1, 2, [3, 4]];console.log(arr1.flat()) // [0, 1, 2, 3, 4] 默认会平铺开展一层const arr2 = [0, 1, 2, [[[3, 4]]]]console.log(arr2.flat(2)) // [0, 1, 2, [3, 4]] 指定开展两层
代码实现
点击查看源码实现
Array.prototype.flat2 = function (depth = 1) { const result = [] const flat = (arr, depth) => { for (let item of arr) { // 当层数还未全副开展的时候,进行递归解决 if (Array.isArray(item) && depth > 0) { flat(item, depth - 1) } else { // 去除空元素,增加非undefined元素 item !== void 0 && result.push(item) } } } flat(this, depth) return result}
测试一把
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]]
24. flatMap
根本应用
flatMap
办法首先应用映射函数映射每个元素,而后将后果压缩成一个新数组。它与 map 连着深度值为1的 flat 简直雷同。 mdn
let arr = [1, 2, 3, 4]arr.flatMap(x => [x * 2]) // [2, 4, 6, 8]
代码实现
点击查看源码实现
Array.prototype.flatMap2 = function (callback, thisCtx) { if (typeof callback !== 'function') { throw `${callback} is not a function` } // map和flat具体实现能够看map.js和flat.js return this.map(function (it, i, array) { return callback.call(thisCtx, it, i, array) }).flat(1)}
测试
let arr = [1, 2, 3, 4]arr.flatMap2(x => [x * 2]) // [2, 4, 6, 8]
结尾
国庆将至,祝大家节日快乐,浪浪浪七天乐。
文章中可能蕴含实现有问题或者不够充沛的状况,欢送大家在评论区指出,肯定快马加鞭地改过,拜谢。
篇幅起因,还有不少数组办法没有写在文章中,如果对大家有一些用途,后续还会出一篇
splice
、keys
、values
...等残余函数的原生实现。祝大家晚安啦