kd-cloud-web / Blog

一群人, 关于前端, 做一些有趣的事儿
13 stars 1 forks source link

关于JS函数式编程简介 #45

Open Hibop opened 4 years ago

Hibop commented 4 years ago

TOC


Functional programming is a programming paradigm

1.treats computation as the evaluation of mathematical functions

2.avoids changing-state and mutable data

by wikipedia

三个要点: **编程范式**,**类数学函数**, **避免数据和状态改变**

编程范式从概念上来讲指的是编程的基本风格和典范模式。
换句话说其实就是程序员对于如何使用编程来解决问题的**世界观和方法论**。
- 声明式(Declarative)   What ==> 表达式     函数式
- 命令式(Imperative)    How ==> 语句(for,if, throw etc.)  面向对象
` JavaScript 是一门基于原型(prototype-based)的多范式语言。`

```js
// 得到一个数组每个数据平方后的和

// 命令式
function mysteryFn (nums) {
  let squares = []
  let sum = 0                           // 1. 创建中间变量

  for (let i = 0; i < nums.length; i++) {
    squares.push(nums[i] * nums[i])     // 2. 循环计算平方
  }

  for (let i = 0; i < squares.length; i++) {
    sum += squares[i]                   // 3. 循环累加
  }

  return sum
}

// 以上代码都是 how 而不是 what...

// 函数式
const mysteryFn = (nums) => nums
  .map(x => x * x)                      // a. 平方
  .reduce((acc, cur) => acc + cur, 0)   // b. 累加
面向对象语言的问题是,它们永远都要随身携带那些隐式的环境。
你只需要一个香蕉,但却得到一个拿着香蕉的大猩猩...以及整个丛林。

by Erlang 作者:Joe Armstrong

避免改变状态和可变数据 (immutable)

Shared mutable state is the root of all evil

共享可变状态是万恶之源

by Pete Hunt

image

const obj = { val: 1 }
someFn(obj)
console.log(obj) // ???

var let const 区别与使用

  • var声明变量可以重复声明,而let不可以重复声明
  • var是不受限于块级的,而let是受限于块级
  • var会与window相映射(会挂一个属性),而let不与window相映射
  • var可以在声明的上面访问变量,而let有暂存死区,在声明的上面访问变量会报错
  • const声明之后必须赋值,否则会报错
  • const定义不可变的量【引用型除外】,改变了就会报错
  • const和let一样不会与window相映射、支持块级作用域、在声明的上面访问变量会报错,

函数是“一等公民”(first class)

纯函数:对于相同的输入,永远会得到相同的输出,而且没有任何可观察的副作用


const double = x => x * 2
const addFive = x => x + 5
const num = double(addFive(10))

num === double(10 + 5) === double(15) === 15 * 2 === 30

// 非纯函数 var a = 11; function add(x) { return x+a; } add(5);

副作用(Side Effects)
- 更改文件系统
- 往数据库中插入记录
- 发送一个 http 请求
- 改变数据
- 打印 log
- 获取用户输入
- DOM 查询
- 访问系统状态
这并不是说,要禁止使用一切副作用,而是说,要让它们在可控的范围内发生。

#### 滥用匿名函数
```js
// 太傻了
const getServerStuff = function (callback) {
  return ajaxCall(function (json) {
    return callback(json)
  })
}

// 这才像样
const getServerStuff = ajaxCall

// 下面来推导一下...
const getServerStuff
  === callback => ajaxCall(json => callback(json))
  === callback => ajaxCall(callback)
  === ajaxCall

// from JS函数式编程指南
const BlogController = (function () {
  const index = function (posts) {
    return Views.index(posts)
  }

  const show = function (post) {
    return Views.show(post)
  }

  const create = function (attrs) {
    return Db.create(attrs)
  }

  const update = function (post, attrs) {
    return Db.update(post, attrs)
  }

  const destroy = function (post) {
    return Db.destroy(post)
  }

  return { index, show, create, update, destroy }
})()

// 以上代码 99% 都是多余的...

const BlogController = {
  index: Views.index,
  show: Views.show,
  create: Db.create,
  update: Db.update,
  destroy: Db.destroy,
}

// ...或者直接全部删掉
// 因为它的作用仅仅就是把视图(Views)和数据库(Db)打包在一起而已。

// from JS函数式编程指南

为何钟爱一等公民?

多包一层的写法最大的问题就是,一旦内部函数需要新增或修改参数,那么包裹它的函数也要改...

// 原始函数
httpGet('/post/2', function (json) {
  return renderPost(json)
})

// 假如需要多传递一个 err 参数
httpGet('/post/2', function (json, err) {
  return renderPost(json, err)
})

// renderPost 将会在 httpGet 中调用,
// 想要多少参数,想怎么改都行
httpGet('/post/2', renderPost)

why函数式编程?

函数式编程高阶用法

link: https://slides.com/yuanhobop/functional-programming-in-javascript-c6aacd#/