map、reduce、filter等高阶函数

forEach、map、reduce、filter高阶函数

高阶函数,指的是JavaScript的函数其实都指向某个变量。既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称为高阶函数。

1、forEach

其中forEach方法中的function回调支持三个参数,第一个是遍历的数组内容;第二个的应用的数组索引,第三个是数组本身。

1
[].forEach(funciton(value,index,array))

同时forEach也是可以第一个参数传回调,第二个参数传this,去改变,不传则默认为window,严格模式下将会是undefined。

1
2
3
4
var arr = [1,2,3]
delete arr[1]; //移除2
console.log(arr)// 1,,3
array.forEach(alert) //弹出1和3

同时forEach是不会遍历空元素的。

2、map
1
2
3
4
array.map(callback,[ thisobject ])
[].map(function(value, index, array){
//...
})

就是将原来的数组映射成新的数组

callback需要return值,不然将全部是undefined

1
2
3
4
5
6
7
8
9
10
11
12
Array.prototype.mymap = function (fn, context) {  // 手写
let arr = [];
let _this = context ? contet : this;
if (fn instanceof Function) {
_this.forEach((item, _this) => {
arr.push(fn.call(_this, item));
})
} else {
throw new Error("${fn} is not a function")
}
return arr;
}
3、filter

这就是一个过滤器,语法类似mapjsilter的callback需要返回布尔值,true表示通过的,false表示不需要的

1
2
3
4
5
6
7
8
9
10
11
12
13
Array.prototype.myfilter = function (fn, context) {  // 手写
let arr = [];
let _this = context ? context : this;
if (fn instanceof Function) {
_this.forEach(element => {
if (fn(element))
arr.push(element);
});
} else {
throw new Error("func is not a function")
}
return arr;
}
4、reduce

功能是用于迭代的

1
arr.reduce(callback,[initialValue])

其中callback可以包含四个参数

  • previous:上次调用回调返回的结果,或者是提供的初始值(initialValue)
  • currentValue(数组当前被处理的元素)
  • index(当前元素在数组中的引用)
  • array(调用reduce的数组)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//数组去重
let arr = [1,2,3,4,4,1]
let newArr = arr.reduce((pre,cur)=>{
if(!pre.includes(cur))
return pre.concat(cur);
else return pre;
},[])

//将二维维数组转换为一维
let arr = [[0,1], [2,3], [4,5]]
let newArr = arr.reduce((pre,cur)=>{
return pre.concat(cur)
},[])
console.log(newArr);

//来改进一下,把多维数组转换成一维数组,递归实现
let arr = [[0,1],[2,3],[4,[5,6,7]]]
const newArr = function(arr){
return arr.reduce((pre,cur)=>pre.concat(Array.isArray(cur)?newArr(cur):cur),[])
}
5、flat
1
2
3
4
5
6
7
Array.prototype.flat(level) //将数组拉平,level可以写入拉平的层次

//如果不管多少层嵌套都要转换成一维数组,可以使用Infinity关键字作为参数
arr.flat(Infinity)

//如果原来数组有空位,会跳过空位
[1,2,,4,5].flat() //[1,2,4,5] 不传参数默认是一层

同时还有一个flatMap方法,相当于对原数组每个元素执行一次map,再拉平

1
2
3
4
5
6
7
//日常手写一遍
Array.prototype.myflat = fucntion(d=1){
let arr = this
return d>0?reduce((acc,cur) => {
acc.concat(Array.isArray(val)?val.myflat(d-1):val)
},[]):arr.slice()
}
6、手写instanceof
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function instance_of(L, R) {
const baseType = ['string', 'number', 'boolean', 'undefined', 'symbol']
if (baseType.includes(typeof (L))) {
return false;
}
let RP = R.prototype;
L = L.__proto__;
while (true) {
if (L === null) {
return false;
}
if (L === RP) {
return true;
}
L = L.__proto__;
}
}
console.log(instance_of(Array, Object))
console.log(Array instanceof Object)
7、call、apply、bind
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
//call
Function.prototype._call = function(obj){
var _obj = obj ? Object(obj) : window
_obj.fn = this;
var argArr = Array.from(arguments).slice(1)
_obj.fn(...argArr);
delete _obj.fn
}

function test(X,y,z){
console.log(X+y+z)
console.log(this.name);
}
var obj = {
name:'啥名字'
}
test._call(obj,'啥','名','字');
console.log(obj)

//apply
Function.prototype._apply = function(obj, argArr) {
// 如果obj不存在则默认window对象
var _obj = obj ? obj : window
// 给_obj添加fn方法
_obj.fn = this
// 获取第二个数组参数
var arg = []
// 当这个参数数组不存在或者为空时,直接执行函数,否则把数组拆分后传递给函数并执行
if (!argArr || argArr.length == 0) {
_obj.fn()
} else {
for (var i = 0; i < argArr.length; i++) {
arg.push(argArr[i])
}
//eval("_obj.fn(" + arg + ")")
_obj.fn(...arg);
}
// 移除这个方法
delete _obj.fn
}

function test(x,y,z) {
console.log(x+y+z);
console.log(this.name);
}
var obj = {
name: '前端菜鸟库'
}
test._apply(obj, ['菜鸟', '库','233']) // 前端菜鸟库
console.log(obj) // {name: "前端菜鸟库"}

//bind
Function.prototype._bind = function (obj) {
if(typeof(this) !== "function"){
throw Error("调用_bind方法的必须为函数")
}
var args = Array.prototype.slice.call(arguments,1)
var _fn = this;
var bindFn = function(){
var newArgs = Array.prototype.slice.call(arguments)
var _obj = this.constructor === _fn ? this:obj
_fn.apply(_obj,newArgs.concat(args))
}
var ProtoFn = function(){}
ProtoFn.prototype = _fn.prototype
bindFn.prototype = new ProtoFn()
return bindFn;
}

var obj = {
name: "前端菜鸟库"
}
function test(x,y,z) {
this.age = '18'
console.log(this.name) // 前端菜鸟库
console.log('x:',x,'y:',y,'z:',z) // x: 1 y: 2 z: 3
console.log(x+y+z) // 6
}
test.prototype.book = "JS"
var Bound = test._bind(obj, 1, 2, 3)
Bound()

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!