本文将手写数组的常用方法
在我们常用到的forEach,map,filter,some,every,reduce….,你会发现,这些方法基本都是传入一个函数,然后对数据加工,处理,返回我们想要的结果。
map
map:
不会对空数组检测
返回一个新的数组
- 语法
array.map(function(currentValue,index,arr), thisValue)
复制代码
Array.prototype._map = function (fn, thisArr) {
if (this == undefined) {
throw new TypeError('this is null or not undefined');
}
if (Object.prototype.toString.call(fn) !== '[object Function]') {
throw new TypeError(fn + 'is not a function');
}
let res = []
let mapArr = this // [1, 2, 3]
for (let i = 0; i < mapArr.length; i++) {
res[i] = fn.call(thisArr, mapArr[i], i, mapArr)
}
return res
}
let arr = [1, 2, 3]
let mapRes = arr._map((val, index, item) => {
return val + 1
})
console.log(mapRes)// [2,3,4]
复制代码
所谓的这些个方法, 就是内部封装好了,方便使用。比如手写map,
- 因为返回新数组,所以要声明一个空数组,然后return出去,里面做的事,就是把每一次调用fn,并且给fn赋值这件事。赋值给返回的新数组。等到你用map的时候,就是看到了具体的逻辑操作,eg:
val+1
。内部怎么得到的val,index,item, 每一项是怎么对应的,你不用关心
forEach
forEach:
空数组是不会执行回调函数的。
改变原数组
返回值是undefined
- 语法
array.forEach(function(currentValue, index, arr), thisValue)
复制代码
- 具体实现可以参考map,map是返回一个新数组,forEach是直接改变原数组。
filter
filter:
不会对空数组进行检测
返回一个新的数组
- 语法
array.filter(function(currentValue, index, arr), thisValue)
复制代码
Array.prototype._filter = function (fn, thisArr) {
if (this == undefined) {
throw new TypeError('this is null or not undefined');
}
if (Object.prototype.toString.call(fn) !== '[object Function]') {
throw new TypeError(fn + 'is not a function');
}
let filterArr = this
let filterRes = []
for (let i = 0; i < filterArr.length; i++) {
if (fn.call(thisArr, filterArr[i], i, filterArr)) {
filterRes.push(filterArr[i])
}
}
return filterRes
}
let arr = [1, 2, 3]
let filRes = arr._filter((val, index, item) => {
return val > 1
})
console.log(filRes)// [2,3]
复制代码
-
filter方法,是筛选数据。当
满足条件
时,返回满足条件的值
-
满足条件 : if (fn.call(thisArr, filterArr[i], i, filterArr)) {}
-
满足条件的值: filterRes.push(filterArr[i])
some
some:
不会对空数组进行检测
返回一个新的数组
- 语法
array.some(function(currentValue, index, arr), thisValue)
复制代码
Array.prototype._some = function (fn, thisArr) {
if (this == undefined) {
throw new TypeError('this is null or not undefined');
}
if (Object.prototype.toString.call(fn) !== '[object Function]') {
throw new TypeError(fn + 'is not a function');
}
let someArr = this
for (let i = 0; i < someArr.length; i++) {
if (fn.call(thisArr, someArr[i], i, someArr)) {
return true
}
}
return false
}
let arr = [1, 2, 3]
let someRes = arr._some((val, index, item) => {
return val > 1
})
console.log(someRes)// true
复制代码
- some也是筛选数据,只是他返回的是true/false。如果有
一个
元素满足条件,则返回true
,剩余的元素不会再执行检测
。
every
- every也是筛选数据。只是他返回的是true/false。如果
所有元素都满足条件
,则返回true
, 只要有一个元素不满足条件,就返回false
Array.prototype._every = function (fn, thisArr) {
if (this == undefined) {
throw new TypeError('this is null or not undefined');
}
if (Object.prototype.toString.call(fn) !== '[object Function]') {
throw new TypeError(fn + 'is not a function');
}
let everyArr = this
for (let i = 0; i < everyArr.length; i++) {
if (!fn.call(thisArr, everyArr[i], i, everyArr)) {
return false
}
}
return true
}
let arr = [1, 2, 3]
let everyRes = arr._every((val, index, item) => {
return val > 0
})
console.log(everyRes)// true
复制代码
-
every和some的实现,我觉得很有意思
-
every是所有的满足条件,才返回true。所以要先判断
-
if (!fn.call(thisArr, everyArr[i], i, everyArr)) {
return false
} -
some是只要有一个满足条件,就返回true.所以要先判断
-
if (fn.call(thisArr, everyArr[i], i, everyArr)) {
return true
} -
你品,你细品?
reduce
- reduce 法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。
- 语法
array.reduce(function(total, currentValue, currentIndex, arr), initialValue)
复制代码
Array.prototype._reduce = function (fn, init) {
if (this == undefined) {
throw new TypeError('this is null or not undefined');
}
if (Object.prototype.toString.call(fn) !== '[object Function]') {
throw new TypeError(fn + 'is not a function');
}
let reduceArr = this
let index = arguments.length === 1 ? 1 : 0 // 求索引。如果没有传初始值,那么index就是1,因为没有传初始值,prev就是初始值,下标是0,那么自然curr下标就是1
let prev = arguments.length === 1 ? reduceArr[0] : init // 求初始值。如果没有传入初始值,那么初始值就是数组的第一项,否则就是传入的初始值init
for (let i = index; i < reduceArr.length; i++) {
prev = fn(prev, reduceArr[i], i, reduceArr) // 迭代累加
}
return prev
}
let arr = [1, 2, 3]
let reduceRes = arr._reduce((prev, curr) => {
return prev + curr
})
console.log('reduceRes', reduceRes)// 6
let reduceResParams = arr._reduce((prev, curr) => {
return prev + curr
}, 2)
console.log('reduceResParams', reduceResParams)// 8
复制代码
- argument是类数组,用于接收传入的不定参数,如果argument.length === 1 代表没有传入参数,可自行输出观察
- reduce的index是一个需要注意的点,因为如果
传入初始值
,那么当前值curr
是从第一个
算起,所以index是0
,如果没有传入初始值
,那么curr
是从第二个
开始算起,所以index是1
- reduce的prev初始值。如果
传入初始值
,那么初始值是init
, 没有传入初始值,初始值则是数组的第一个元素reduceArr[0]
- reduce作为一个累加器,可以想成是
a = a+ 1
的简单逻辑.换成代码就是
prev = fn(prev, reduceArr[i], i, reduceArr) // 迭代累加
复制代码
includes
-
方法用于判断字符串是否包含指定的子字符串。
-
如果找到匹配的字符串则返回 true,否则返回 false。
-
语法
String.includes(searchvalue, start)
Array.includes(searchvalue, start)
复制代码
Array.prototype._includes = function (searchElement, formIndex = 0) {
let includesEle = this
let len = includesEle.length
if (searchElement.length >= len || !len) return false // 如果传入起始位大于数据的长度,或者没有数据的
for (let i = formIndex; i < len; i++) {
if (includesEle[i] === searchElement) // 当传入的数据和查找的数据一致,返回true
return true
}
return false
}
let arr = [1, 2, 3]
let includes = arr._includes(1)
console.log('includes', includes)// true
复制代码
- 这里判断了
len
的存在,和 if (this == undefined) {
throw new TypeError(‘this is null or not undefined’);
}是一个道理
indexOf
-
indexOf(item, start) start为开始检索位置,找到返回下标值,没找到返回-1
-
他的实现和includes可以说一模一样。includes 是返回true/ false ,那么indexOf中,true就是返回数组下标,false就是返回-1
rray.prototype._indexOf = function (searchElement, formIndex = 0) {
let indexOf = this
let len = indexOf.length
if (searchElement.length >= len || !len) return -1 // 如果传入起始位大于数据的长度,或者没有数据的
for (let i = formIndex; i < len; i++) {
if (indexOf[i] === searchElement) // 当传入的数据和查找的数据一致,返回true
return i
}
return -1
}
let arr = [1, 2, 3]
let _indexOf = arr._indexOf(3)
let _indexOf2 = arr._indexOf(33)
console.log('_indexOf', _indexOf)// 2
console.log('_indexOf2', _indexOf2)// -1
复制代码
总结
-
在所以的方法里,都是传入一个函数,那么首先就是要判断是否是函数
Object.prototype.toString.call(fn) !== '[object Function]' typeof fn !== 'function' 复制代码
-
我们在用的过程中,其实thisValue这个参数,一般都不写,所以在文中遇到fn.call(thisArr, filterArr[i], i, filterArr) 可直接写成fn(filterArr[i], i, filterArr) 。我这里是为了迎合他的用法?
thisValue:可选。传递给函数的值一般用 “this” 值。
如果这个参数为空, “undefined” 会传递给 “this” 值
- 关于this,我们记的是,谁调用他,他就指向谁,他在指向的同时,其实,
this也代表了指向的那个数据
。比如let filterArr = this 这是一种很好的获取调用者数据
的方式 - 返回的是新数据,所以要声明一个空数组 然后将其return出去
- 以上手写,发现有很多相似之处
Array.prototype._every = function (fn, thisArr) {
if (this == undefined) {
throw new TypeError('this is null or not undefined');
}
if (Object.prototype.toString.call(fn) !== '[object Function]') {
throw new TypeError(fn + 'is not a function');
}
let everyArr = this
for (let i = 0; i < everyArr.length; i++) {
}
}
复制代码