欢迎来到好多视频第238期,来用函数式编程的思路实现一下数组筛选功能,过程中代码会不断迭代,一起来看看函数式编程有什么特点,用了它有什么好处。

用普通 for 循环实现筛选

先用最朴素的循环思路,实现一下筛选。

const users = [
  {
    name: 'peter',
    gender: 'male'
  },
  {
    name: 'billie',
    gender: 'female'
  }
]

let arr = []

for (let i = 0; i < users.length; i++) {
  if (users[i].gender === 'female') arr.push(users[i])
}

console.log(arr)

创建 index.js 文件,咱们要处理的数据就是 users ,是一个对象数组,每个对象中包含姓名和性别。

下面我要把数组中的女性筛选出来,先定义一个空数组。从 i = 0 开始迭代,把每一个数组元素都拿出来,判断他的性别是不是女性,如果是,就 push 到空数组中。

最后把数组打印出来。

到终端中,运行 node index.js 可以看到打印出的数组中只保留了女性。

使用函数式编程重构

下面来用函数式编程的思路重构这个效果。函数式编程的基本原则就是,所有的东西都封装到函数里。这里的函数可不是任意的,必须是纯函数,应该只受到输入,也就是参数的值,的影响,同时也只关注自己要输出的内容,也就是 return 的值。

其他的事情一概不做,例如生成各种副作用,比如打印信息啦,保存数据啦,发送网络请求啦,同时也不能修改传入的参数,

Array.prototype.myFilter = function (callback) {
  arr = []
  for (let i = 0; i < this.length; i++) {
    if (callback(this[i]))
      arr.push(this[i])
  }
  return arr
}

const female = users.myFilter(user => { 
  return user.gender === 'female' 
})

console.log(female)

数组的 prototype 里添加一个 myFilter 函数,filter 的中文意思是筛选。把原有的迭代逻辑封装起来, users 替换为 this 所指代的当前数组。

然后把 if 括号中的判断逻辑抽出到 callback 函数中。

这里 myFilter 是一个所谓的高阶函数,因为他会把其他的函数作为自己的参数。而作为人家的参数的函数就被称为回调函数,也就是 callback 。

myFilter 里面传入一个回调函数,还记得咱们前面说的,回调函数的输出要保证只收到它的输入,也就是参数的影响,同时一定要 return 东西,这里就是根据用户性别是不是女性来返回 true 或者 false 。

终端中,运行 node index.js 发现依然是能正确输出的。

复用很方便

逻辑拆分的好处是便于维护和测试,同时也更方便的复用代码。

const isFemale = user => user.gender === 'female'

const female = users.myFilter(isFemale)

在 JS 中,function 也是一个 value ,可以赋值到变量中。来把回调函数抽出,赋值给 isFemale 。

终端中,测试一下,发现依然管用。

也可以再定义 isMale 函数。打印出所有男性同胞。改成判断 isMale ,发现一样好用。

这里的实现的效果是如此的常用,以至于 JS 已经原生集成了 filter 方法。改成原生的 filter 函数,运行结果没有任何的区别。

参考资料