likes
comments
collection
share

函数式编程

作者站长头像
站长
· 阅读数 13

一、编程范式

1、面向过程编程:将编程任务当作完成一件事情,这件事情需要按步骤完成。先做什么,再做什么,然后做什么(注重于步骤)。

2、面向对象编程:把功能组织成对象,然后相关的操作作为对象的方法。

3、函数式编程:把功能分解为一系列独立的函数,通过函数间相互调用来完成功能。

二、函数式的优缺点

优点:

1、函数式编程能提高复用性和扩展性

每个函数就像一块积木,能随时拼入新积木,也能随时取出积木去复用。

比如需要写一个算法:把数字乘以 2 然后减 1(后面需要扩展),分别以面向对象和函数式编写。

面向对象

function CalcNumber(number) {
    this.number = number
}

CalcNumber.prototype.calc = function () {
    return this.number * 2 - 1
}
const a = new CalcNumber(2)
console.log(a.calc()) //3

若其他地方需要在该算法的基础上再除以2,就得写一个子类来继承父类,再重写方法。

//继承构造函数
function CalcNumberSon(number) {
    CalcNumber.call(this, number)
}
//继承原型链
CalcNumberSon.prototype = new CalcNumber()
//重写方法
CalcNumberSon.prototype.calc = function () {
    return (this.number * 2 - 1) / 2
}
const b = new CalcNumberSon(2)
console.log(b.calc()) //1.5

若另一个地方需要的是在该算法的基础上加2(而不是除以2),就又得创建一个子类继承父类,再重写方法...

函数式

function multiplyTow(num) {
    return num * 2
}

function addOne(num) {
    return num - 1
}

var num = multiplyTow(2)
num1 = addOne(num)
console.log(num1) //3

而函数式写法只需要再写一个除以2的函数,在需要的地方调用就行。

function exceptTow(num) {
    return num / 2
}

num2 = exceptTow(num1)
console.log(num2) //1.5

以后需要哪个函数都可以直接拿来随意组合使用。

2、函数式编程能很好的结合 Tree Shaking 去使用,而面向对象编程方案无法记录

缺点:

函数过多比较难管理,逻辑性没有面向对象强。涉及到业务逻辑的代码,还是使用面向对象编程,更加擅长组织逻辑。

三、如何写好函数式编程

1、保证是纯函数:一个函数的返回结果只依赖于它的参数,同样的输入必定得到同样的输出

非纯函数(由于变量 a 是函数 add() 的外部变量且不受该函数控制,故无法保证add()的输出)

var a = 10;

function add(num) {
    return a + num
}

转化为纯函数 -> 只需将a作为参数传入函数中,这时add()输出全都由传入的参数决定。

function add(a, num) {
    return a + num
}

2、减少函数副作用:函数的副作用就是函数会影响外部数据,如全局变量

副作用

var b = 123;

function bPlus() {
    // 若直接操作外部变量,就会改变外部变量
    b += 1;
    return b;
}

bPlus()
console.log(b) //124

消除函数副作用的方法

基本数据类型:将外部变量作为参数传入,然后函数内部创建一个局部变量来操作。

var c = 123;

function cPlus(c) {
    c += 1;
    return c;
}

var c2 = cPlus(c)
console.log(c, c2) //123, 124

引用数据类型:将外部变量作为参数传入,然后函数内部拷贝一份,再去操作拷贝出来的那份

// 对象
var obj = {a: 1};

function objPlus(obj) {
    var _obj = Object.create(obj)
    _obj.a += 1
    return _obj
}

var obj2 = objPlus(obj)
console.log(obj, obj2) //{a: 1}, {a: 2}

// 数组
var arr = [1];

function arrPlus(arr) {
    var _arr = [...arr]
    _arr[0] += 1
    return _arr
}

var arr2 = arrPlus(arr)
console.log(arr, arr2) //[1], [2]

3、工程化下的函数编程

传统的面向对象,直接暴露类。

function class1() {
}

// es6
export default class1;  //暴露
import class1 from './xx.js';   //引入

// commonjs
module.exports = class1;
const class1 = require('./xx.js')

函数式

// es6
export function f1() {

}

export function f2() {

}

import {f1} from './xx.js';
import * as all from './xx.js';

// commonjs
function f1() {

}

function f2() {

}

exports.f1 = f1;
exports.f2 = f2;

const f1 = require('./xx.js').f1;
const all = require('./xx.js');