# JavaScript教程 - 11 函数进阶

# 11.1 高阶函数

什么是高阶函数?

满足以下两种情况之一的函数就是高阶函数:

  1. 函数作为参数传入
  2. 函数作为返回值返回

高阶函数有什么作用呢?

高阶函数能让你写出更简洁、可复用、模块化的代码,它是回调函数、事件处理、函数组合等场景的核心。

下面慢慢讲。

# 1 函数作为参数

例如,我们现在有一个学生列表:

class Student {
  constructor(name, chinese, math, english) {
    this.name = name;
    this.chinese = chinese;
    this.math = math;
    this.english = english;
  }
}

// 学生列表
const allStuList = [
  new Student("zhangsan", 87, 48, 92),
  new Student("lisi", 47, 92, 71),
  new Student("wangwu", 58, 46, 38),
  new Student("zhangliu", 95, 91, 99),
];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

现在分别想查询列表中:语文成绩不及格的同学、所有课程不及格的同学、所有课程都是优秀的学生,那么我们需要定义三个函数,如下:

// 学生列表
const allStuList = [
  new Student("zhangsan", 87, 48, 92),
  new Student("lisi", 47, 92, 71),
  new Student("wangwu", 58, 46, 38),
  new Student("zhangliu", 95, 91, 99),
];

// 获取语文成绩不及格的同学
function getChineseFlunkList() {
  const stuList = [];
  for (let stu of allStuList) {
    if (stu.chinese < 60) {
      stuList.push(stu);
    }
  }
  return stuList;
}

// 获取所有课程不及格的同学
function getFlunkList() {
  const stuList = [];
  for (let stu of allStuList) {
    if (stu.chinese < 60 && stu.math < 60 && stu.english < 60) {
      stuList.push(stu);
    }
  }
  return stuList;
}

// 获取所有课程都是优秀的学生
function getExcellentList() {
  const stuList = [];
  for (let stu of allStuList) {
    if (stu.chinese >= 90 && stu.math >= 90 && stu.english >= 90) {
      stuList.push(stu);
    }
  }
  return stuList;
}

// -------------方法调用---------------------
console.log("语文不及格的同学:");
const chineseFlunkList = getChineseFlunkList();
for (let stu of chineseFlunkList) {
  console.log(stu);
}

console.log("所有不及格的同学:");
const flunkList = getFlunkList();
for (let stu of flunkList) {
  console.log(stu);
}

console.log("所有成绩都是优秀的同学:");
const excellentList = getExcellentList();
for (let stu of excellentList) {
  console.log(stu);
}
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
  • 在上面的代码中,定义了3个函数 getChineseFlunkList()getFlunkList()getExcellentList(),但是三个函数中只有其中的判断条件不同,代码比较冗余, 能否抽出判断条件,将判断条件作为参数传递呢?

我们先抽出一个公共的函数,根据传递的参数条件获取学生列表的函数:

// 根据条件获取学生列表
function filter(funCondition) {
  const stuList = [];
  for (let stu of allStuList) {
    if (funCondition(stu)) {
      stuList.push(stu);
    }
  }
  return stuList;
}
1
2
3
4
5
6
7
8
9
10
  • 上面的函数的参数也是一个函数,在函数中,调用传递的函数,根据函数的结果判断 stu 是否满足条件。
  • 这样就可以传递一个函数,具体判断的条件,在传递的函数中实现就可以了,返回 true 就是满足条件。

下面来调用上面的函数:

// 使用示例
console.log("语文不及格的同学:");
const chineseFlunkList = filter((stu) => {return stu.chinese < 60});
for (let stu of chineseFlunkList) {
  console.log(stu);
}
1
2
3
4
5
6
  • 调用函数,并传递一个函数作为参数,为了简单,直接传递一个箭头函数就可以了。

  • stu.chinese < 60 表示如果学生的中文成绩大于60就返回true,那么在 filter() 函数中调用传递的函数,就可以根据结果筛选学生了。

箭头函数还可以再简化一下,获取三个学习列表,可以这样写:

// 使用示例
console.log("语文不及格的同学:");
const chineseFlunkList = filter((stu) => stu.chinese < 60);
for (let stu of chineseFlunkList) {
  console.log(stu);
}

console.log("所有不及格的同学:");
const flunkList = filter(
  (stu) => stu.chinese < 60 && stu.math < 60 && stu.english < 60
);
for (let stu of flunkList) {
  console.log(stu);
}

console.log("所有成绩都是优秀的同学:");
const excellentList = filter(
  (stu) => stu.chinese >= 90 && stu.math >= 90 && stu.english >= 90
);
for (let stu of excellentList) {
  console.log(stu);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

通过函数式编程,代码的冗余度降低了,代码更简洁了。

这种方式更符合编程的 OCP (Open-Closed Principle)原则,对扩展开放,对修改关闭。如果有其他的查询学生的条件,直接扩展即可,不用修改 filter() 函数。

# 2 函数作为返回值

函数作为返回值也经常被用到。

内容未完......