用法
可以遍历数组的每个元素,执行特定的操作:
// res 为 undefined const res = ['a','b','c'].forEach(function(item,index,arr){ console.log(`${index}-${item}`,arr,this) return 123 },{}) // 遍历过程中即使push了新元素,也仍然按照原数组长度进行遍历。打印 1,2 [1,2].forEach((item,index,arr) => { arr.push(3,4,5) console.log(item) }) // 遍历过程中可以提前修改未遍历元素。打印 1,100 [1,2].forEach((item,index,arr) => { arr[1] = '100' console.log(item) }) // 遍历过程中可以 return,但只是结束当前这次遍历,无法跳出整个 forEach。打印 2 [1,2].forEach((item,index,arr) => { if(index == 0) return console.log(item) }) // 遍历过程中会自动跳过 empty 元素(null 和 undefined 不会跳过)。打印 1,2,4 [1,2,,4].forEach((item,index,arr) => { console.log(item) })
实现
Array.prototype.myforEach = function (fn,thisArg = null){ if(typeof fn != 'function'){ throw new TypeError(`${fn} is not a function`) } let arr = this for(let i = 0,len = arr.length;i < len;i++){ // 如果不是 empty 元素 if(i in arr){ fn.call(thisArg,arr[i],i,arr) } } }
用法
将原数组的每个元素映射为执行回调函数之后的返回值:
forEach
差不多,也是会跳过 empty 元素// 返回新数组 [2,4,6,8] [1,2,3,4].map((item,index) => item * 2)
实现
Array.prototype.myMap = function(fn,thisArg = null){ if(typeof fn != 'function'){ throw TypeError(`${fn} is not a function`) } let arr = this // 这里不要使用 let newArr = [],否则修改原数组长度时会影响新数组长度 let newArr = new Array(arr.length) for(let i = 0,len = arr.length;i < len;i++){ if(i in arr){ const res = fn.call(thisArg,arr[i],i,arr) newArr[i] = res } } return newArr }
用法
flatMap
相当于是 map
和 flat(1)
的结合。它会给某个数组调用 map
方法,如果得到了一个多维数组,则会对该数组进行一次降维。
PS:注意这个方法不会改变原数组。
const arr1 = [1, 2, 3, 4]; arr1.map(x => [x * 2]); // [[2], [4], [6], [8]] arr1.flatMap(x => [x * 2]); // [2, 4, 6, 8]
实现
我们可以在每次执行 flatMap
的回调并返回一个新结果时,判断该结果是不是数组,如果是则取出数组中的每个元素放入最终返回的新数组中。
Array.prototype.myFlatMap = function(fn,thisArg = null){ if(typeof fn != 'function'){ throw new TypeError(`${fn} is not a function`) } let arr = this let newArr = new Array(arr.length) let k = 0 for(let i = 0;i < arr.length;i++){ if(i in arr){ const res = fn.call(thisArg,arr[i],i,arr) if(Array.isArray(res)){ for(let el of res){ newArr[k++] = el } } else { newArr[k++] = res } } } return newArr }
用法
find 返回数组中第一个符合条件的元素或者 undefined:
indexOf
搜索数组,无法自定义搜索条件,所以出现了 find
find
会对每个元素执行一次回调函数,直到找到符合条件的元素,就将这个元素返回(永远只返回一个),并结束函数执行;找不到则返回 undefinedi in arr
的检查[1,2,3,4,5].find((item,index,arr) => item > 2) // 3
实现
Array.prototype.myFind = function(fn,thisArg = null){ if(typeof fn != 'function'){ throw new TypeError(`${fn} is not a function`) } let arr = this for(let i = 0;i < arr.length;i++){ const result = fn.call(thisArg,arr[i],i,arr) if(result){ return arr[i] } } return undefined }
用法
和 find
基本一致,但是 findIndex 返回的是第一个符合条件的元素的索引,没有这样的元素就返回 -1
[1,2,3,4,5].findIndex((item,index) => item > 2) // 2
实现
Array.prototype.myfindIndex = function(fn,thisArg = null){ if(typeof fn != 'function'){ throw new TypeError(`${fn} is not a function`) } let arr = this for(let i = 0;i < arr.length;i++){ const result = fn.call(thisArg,arr[i],i,arr) if(result){ return i } } return -1 }
用法
通过 find
搜索数组,只能找到一个符合条件的元素,而 filter
可以筛选出所有符合条件的元素:
[1,2,3,4,5].filter((item,index) => item > 2) // 返回 [3,4,5] [1,2,3,4,5].filter((item,index) => item > 100) // 没有符合的元素,返回 []
实现
Array.prototype.myFilter = function(fn,thisArg = null){ if(typeof fn != 'function'){ throw new TypeError(`${fn} is not a function`) } let arr = this let res = [] let k = 0 for(let i = 0;i < arr.length;i++){ if(i in arr){ const result = fn.call(thisArg,arr[i],i,arr) // 如果元素符合条件,则放入新数组中 if(result){ res[k++] = arr[i] } } } }
用法
接受一个回调函数表示判断条件,只要数组中有一个元素满足该条件(回调函数返回 true),some
方法就返回 true,否则返回 false
[1,2,3,4].some((item,index) => item>3) // 至少有一个大于3的数,返回 true [1,2,3,4].some((item,index) => item>100) // 没有一个大于100的数,返回 false
实现
Array.prototype.mySome = function(fn,thisArg = null){ if(typeof fn != 'function'){ throw new TypeError(`${fn} is not a function`) } let arr = this for(let i = 0;i < arr.length;i++){ const result = fn.call(thisArg,arr[i],i,arr) if(result){ return true } } return false }
用法
接受一个回调函数表示判断条件,只有数组中所有元素都满足该条件(回调函数返回 true),every
方法才会返回 true,有一个不满足都会返回 false
[1,2,3,4].every((item,index) => item>0) // 所有元素都大于0,返回 true [1,2,3,4].every((item,index) => item>3) // 并非所有元素都大于3,返回 false
实现
Array.prototype.myEvery = function(fn,thisArg = null){ if(typeof fn != 'function'){ throw new TypeError(`${fn} is not a function`) } let arr = this for(let i = 0;i < arr.length;i++){ const result = fn.call(thisArg,arr[i],i,arr) if(!result){ return false } } return true }
用法
reduce
可以归并数组的每个元素,最终构建一个累计归并值作为返回值:
arr.reduce((acc,cur,index,arr) => {...},baseAcc)
acc
,也即累计归并值。初始累计归并值缺省是第一个非 empty 元素,且此时会从该元素的下一个元素开始迭代。// 没有提供初始累计归并值,因此缺省是1,并且从2开始迭代 [1,2,3,4].reduce((acc,cur) => acc + cur) // 10 // 提供100作为初始累计归并值,从1开始迭代 [1,2,3,4].reduce((acc,cur) => acc + cur,100) // 110 // 二维数组转化为一维数组,concat 本身会拍平一维数组 [1,2,[3,4]].reduce((acc,cur) => acc.concat(cur),[]) // [1,2,3,4]
实现
实现的时候,有两个关键的地方:
typeof baseAcc === 'undefined'
判断不准确,因为有可能传的第二个参数确实就是 undefined,这里可以通过剩余参数的长度判断Array.prototype.myReduce = function(...args){ let fn = args[0] let arr = this let len = arr.length let index = 0,acc if(typeof fn != 'function'){ throw new TypeError(`${fn} is not a function`) } // 如果传了第二个参数 if(args.length >= 2){ acc = args[1] } else { // 只要当前数组还没找到非 empty 元素,就一直遍历下去 while(index < len && !(index in arr)){ index++ } // 如果数组是一个充满 empty 元素的空数组,则抛出错误 if(index >= len){ throw new TypeError('Reduce of empty array with no initial value') } // index 加一,表示第一个非 empty 元素的下一个元素 acc = arr[index++] for(;index < len;index++){ if(index in arr){ acc = fn(acc,arr[index],index,arr) } } return acc } }
用法
用法基本和 reduce
一致,区别是它是从后往前去遍历数组的。
[0, 1, 2, 3].reduceRight((acc, cur) => { console.log(cur); }); // 2 // 1 // 0
实现
reduceRight
的实现和 reduce
基本一样,但需要注意:非 empty 元素的查找以及数组的遍历顺序是反过来的
Array.prototype.myReduceRight = function(...args){ let fn = args[0] let arr = this let len = arr.length let index = len - 1,acc if(typeof fn != 'function'){ throw new TypeError(`${fn} is not function`) } if(args.length >= 2){ acc = args[1] } else { while(index > 0 && !(index in arr)){ index-- } if(index == 0){ throw new TypeError('Reduce of empty array with no initical value') } acc = arr[index--] for(;index >= 0;index--){ if(index in arr){ acc = fn(acc,arr[index],index,arr) } } return acc } }