我们可以先预习一下 JS中数组方法汇总 的内容。

forEach

基本使用

该方法有一个参数,且该参数是一个 function,而它也有三个参数,分别是:valueindexarray。并且它的 this 指向 window

1
2
3
4
5
6
7
8
9
10
11
let arr = [{
id: 0,
name: 'lq'
}, {
id: 1,
name: 'zww'
}]

arr.forEach(function(value, index, array) {
console.log(this) // window
})

我们可以自定义 function 内部的 this 指向。

forEach 的第二个参数可以设置 function 内部的 this 指向。如果不传将默认指向 window

1
2
3
arr.forEach(function(value, index, array) {
console.log(this) // [{…}, {…}]
}, arr)

封装

现在我们来自己封装一下该方法的功能:

1
2
3
4
5
6
7
8
9
Array.prototype.myForEach = function(fn) {
var arr = this,
len = arr.length,
arg2 = arguments[1] || window // 如果传了第二个参数,那 this 执行它,如果没传则指向 window

for (var i = 0; i < len; i++) {
fn.apply(arg2, [arr[i], i, arr])
}
}

下面就来使用一下封装的方法:

1
2
3
4
5
6
7
8
9
10
11
12
let arr = [{
id: 0,
name: 'lq'
}, {
id: 1,
name: 'zww'
}]

arr.myForEach(function(value, index, array) {
console.log(value)
console.log(this)
}, arr)

当我们执行后发现与 forEach 功能一致。


filter

基本使用

它与 forEach 的参数一致,但是它会返回一个新数组

它也会像 forEach 一样进行循环,但是在循环的过程中必须接收一个返回值,如果返回值为 true,那么循环的本次数据将会进入新的数组里,如果为 false,则不会进入。

假设我们要给一个数组的每一项都添加一个字段,可以这样写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let arr = [{
id: 0,
name: 'lq'
}, {
id: 1,
name: 'zww'
}]

var newArr = arr.filter(function(value, index,array) {
value.name = this.like + value.name
return value.id === 0
}, { like: 'hhhh' })

console.log(newArr) // [{…}]

但是,当我们打印出原数组 arr 时,会发现原数组也发生了改变,这并不是我们想要的。


封装

下面我们就来自己封装一下 filter,并解决原数组被修改的问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Array.prototype.myFilter = function(fn) {
var arr = this,
len = arr.length,
arg2 = arguments[1] || window,
newArr = [],
newItem
for (var i = 0; i < len; i++) {
newItem = deepClone(arr[i], {})
fn.apply(arg2, [newItem, i, arr]) ? newArr.push(newItem) : ''
}
return newArr
}

function deepClone(org, tar) {
var tar = tar || {}
var toStr = Object.prototype.toString
var arrType = '[object Array]'
for (var key in org) {
if (org.hasOwnProperty(key)) {
if (typeof(org[key]) === 'object' && org[key] !== null) {
tar[key] = toStr.call(org[key]) === arrType ? [] : {}
deepClone(org[key], tar[key])
} else {
tar[key] = org[key]
}
}
}
return tar
}

当我们使用后会发现,功能与 filter 一致,并且原数组不会发生改变。


map

它与 filter 功能差不多,但是 map 可以直接修改数据进行返回