JavaScript函数式编程入门

131 阅读3分钟

JavaScript ES6 函数式编程指南入门

1.简介

1.1 什么是函数式编程?

  f(x) = y

不就是尽量以函数的形式的形式写代码吗?

是的!

但是函数的形式要遵守一定的规则,然后可以达到很好的效果,

但是其中要有几点是要必须遵守的。

  • 函数总是接收 一个 参数
  • 函数总是返回 一个
  • 对于相同的输入都将返回相同的值
  • 函数逻辑不依赖其他全局变量

至于这样写的好处,暂时还未品尝到。暂时还是先把概念搞清楚。 (后续更新)

  1. 缓存

1.2 引用透明性

相同的输入都将返回相同的值,这个特性又被叫做引用透明性。

下面的这个过程被称为:替换模型(Substitution Model)

  const identity = i => i;

  1 + identity(1)
  // 等同于
  1 + 1

这个好处就是可以用作缓存。 假设有一个函数式算 一个数的阶乘。 输入: 5 输出:120, 加入再次输入5, 根据特性,就知道结果依然是 120(并且只依赖一个输入:5),. 有了这个特性之后,就可以用一个变量来缓存 输入: 5 的结果。 再次输入5:直接将缓存结果返回,无需重复计算

1.3 声明式、命令式、抽象

函数式编程主张声明式编程和编写抽象代码

  • 命令式:告诉编译器“如何做”
  • 声明式:告诉编译器“做什么”
  // 告诉编译器 做什么,获得数组长度,循环数组,等等。。。
  const array = [1,2,3]
  for(i = 0; i < array.length; i++){
    console.log(i)
  }
  const array = [1,2,3]
  // 这里只做了一个 “如何做”的抽象函数
  array.forEach(item => { console.log(item )})

1.4 纯函数

纯函数的定义是,对于相同的输入,永远会得到相同的输出,而且没有任何可观察的副作用,也不依赖外部环境的状态。

1.5 管道与组合

虽然一个函数都只解决一个问题,但是可以使用管道或组合来完成复杂任务。

2.高阶函数(HOC High-Order Function

2.1 理解概念

概念:接收一个函数作为参数并且/或者返回函数作为输出的函数,称为高阶函数。

个人理解:使用函数来代替数据传递

const tellType = (arg) => {
  // 已知tellType 可以判断类型
  if(typeof arg === 'function') {
    arg()
  } else {
    console.log('The passed data is' + arg)
  }
}

const dataFn = () => {
  console.log('I am data function')
}

tellType(dataFn)

这就是一个例子,把函数dataFn, dataFn 也可以理解为数据。 传递给了 tellType, 数据通过函数传递。

2.2 返回一个函数

const crazy = () => String;

const fn = crazy()

console.log(fn('hoc'))

重点: crazy 执行并返回了一个指向 String 的函数引用,注意:只返回了一个函数引用,并没有执行函数

2.3 抽象与高阶函数

高阶函数就是定义抽象。

什么是抽象?与函数式编程有什么关系?

抽象的作用:一辆车,只要加油就能启动,不用去关心具体零部件之间怎样发生作用的。 抽象的目的:达到目标,而不必关心底层的系统概念。

2.4 通过高阶函数实现抽象

如何实现抽象呢?

自己理解:只要目的是达到目标,而不必关心底层具体实现的代码,就可以叫做抽象代码。

上面做了一个 forEach 的抽象函数,这个函数式遍历了数组,那么怎么做一个 遍历对象的 抽象函数呢?

1.遍历给定对象上的所有 key, 2.判断 key 是否属于对象本身 3.如果 步骤2 值为true, 获取 key的值(value)

const obj = {
  name: '111',
  age: 999,
  sex: 'man'
}

const forEachObj = (obj, fn) => {
  for (const key in obj) {
    if (Object.hasOwnProperty.call(obj, key)) {
      const value = obj[key];
      fn(key, value)
    }
  }
}

forEachObj(obj, (key, value) => {
  console.log(key, value)
})

forEach 和 forEachObj 都是高阶函数,他们都使开发者专注于任务(通过传递对应的函数),而抽象出遍历的部分

是否有了更深的理解?