JS函数高级技巧之纯函数、高级函数、懒函数和函数组合

纯函数

首先,纯函数要满足两个条件:

  • 给相同的参数返回相同的结果;
  • 不产生任何副作用
js 复制代码
function double(num){
  return num * 2 
}

只要给num的值不变,它返回的结果也不会变,而且这个函数执行的过程中没有对外界造成影响,所以它是一个纯函数。

不是纯函数的两种类型

  1. 执行结果不一样
js 复制代码
const counter = (function () {
    let initValue = 0;
    return function() {
        initValue++;
        return initValue;
    }
})()
console.log(counter()) // 1
console.log(counter()) // 2
console.log(counter()) // 3
  1. 操作了外部变量,产生了副作用
js 复制代码
let count = 0;
function isYoung(user) {
    if (user.age <= 20) {
        count++;
        return true;
    } else {
        return false;
    }
}
console.log(isYoung({name: 'Tom', age: 25})) // false
console.log(isYoung({name: 'Tom', age: 25})) // false

纯函数的好处

  • 纯函数更清晰更容易理解
  • 对于纯函数,编译器可以做优化
  • 纯函数更易于测试
    纯函数的测试不依赖于外部因素,多亏了纯函数的特性,我们给纯函数编写单元测试时只要简单地给个输入然后判断输出是否与预期一致就好了

高阶函数

同样的,高阶函数也有两个条件:

  • 接受函数作为参数
  • 把函数作为结果返回
    比如:map()函数

懒函数(惰性函数)

视频了解: https://www.bilibili.com/video/BV1Dw411q7ju/?spm_id_from=333.337.search-card.all.click&vd_source=b79be8283df9418cb45941cc0bd583c6

函数体里面会包含各种各样的条件语句,有时候这些条件语句仅仅需要执行一次,比如说我们写单例的时候判断某个对象是否为空,如果为空我们就创建一个对象,那其实我们知道后续只要程序还在运行,这个对象是不可能为空的,但是我们每次使用时都还会判断是否为空,都会执行我们的条件判断。我们可以稍微提升一下性能通过在第一次执行后删除这些条件判断,这样后面就不判断是否为空直接拿来即用了,这就是懒函数。
没有用懒函数

js 复制代码
class User {
    constructor() {
        this.name = 'Tom';
        this.age = 25;
    }
}
// 不使用懒函数
let instance = null;
function user() {
    if (instance !== null) {
        return instance;
    } else {
        instance = new User();
        return instance;
    }
}

上面的代码在每次执行的时候都会执行条件判断,这边还好,如果我们的条件判断非常复杂,那其实也是一个不小的性能影响,这时候我们就可以使用懒函数的小技巧来优化代码

js 复制代码
var user = function () {
    var instance = new User();
    user = function () {
        return instance;
    }
    return user();
}

这样在第一次执行后,我们用一个新函数重写了之前的函数,后面再执行这个函数的时候我们都会直接返回一个固定的值,这无疑会提高我们代码的性能。所以后续我们遇到一些只用执行一次的条件语句,我们都可以用懒函数来优化它,通过使用一个新函数来覆盖原有的函数来移除条件语句。

函数组合

比如:我们这里有三个函数。分别是:

  1. 乘10
  2. 除2
  3. 转为字符串
js 复制代码
const multiply = (x) => x * 10;
const divide = (x) => x / 2;
const toStr = (x) => x.toString()

当我们直接按顺序执行前三个函数时,我们首先会这么写;

js 复制代码
const compute = (x) => toStr(divide(multiply(x)))

这边只有三步,所以看起来不复杂,实际情况是如果有更多的操作的话,层层嵌套很难看也容易出错,类似于这样fn3(fn2(fn1(fn0(x))))。为了避免这种情况,把调用层级扁平化,我们可以写一个compose函数专门用来把函数调用组合到一起。

js 复制代码
const compose = function (fun, f, g) {
    return function (x) {
        return fun(f(g(x)))
    }
}
const computeFun = compose(toStr, divide, multiply)
console.log(computeFun(5)) // "25"
console.log(Object.prototype.toString.call(computeFun(5))) // [object String]

上面这个组合函数只能接收三个函数参数,这边我们编写一个接收任意数量的函数参数

js 复制代码
// 支持任意数量的函数参数
const composeAny = (...funs) => (x) => funs.reduceRight((acc, fun) => fun(acc), x) // reduceRight: 从右往左遍历

const computeFunAny1 = composeAny(divide, divide, multiply)
console.log(computeFunAny1(8)) // 20
console.log(Object.prototype.toString.call(computeFunAny1(8))) // [object Number]
const computeFunAny2 = composeAny(divide, multiply)
console.log(computeFunAny2(5)) // "25"
console.log(Object.prototype.toString.call(computeFunAny2(5))) // [object Number]

const computeFunAny3 = composeAny(toStr, divide, multiply)
console.log(computeFunAny3(8)) // 40
console.log(Object.prototype.toString.call(computeFunAny3(8))) // [object String]
相关推荐
Jtti13 分钟前
PHP在Debian环境上的并发处理能力如何
开发语言·debian·php
时光追逐者18 分钟前
在 Blazor 中使用 Chart.js 快速创建数据可视化图表
开发语言·javascript·信息可视化·c#·.net·blazor
独好紫罗兰20 分钟前
洛谷题单3-P5718 【深基4.例2】找最小值-python-流程图重构
开发语言·python·算法
小天努力学java23 分钟前
【面试题】如何用两个线程轮流输出0-200的值
java·开发语言
云边有个稻草人25 分钟前
【C++】第八节—string类(上)——详解+代码示例
开发语言·c++·迭代器·string类·语法糖auto和范围for·string类的常用接口·operator[]
hz.ts33 分钟前
Angular 国际化
javascript·ecmascript·angular.js
6武734 分钟前
Vue 数据传递流程图指南
前端·javascript·vue.js
夏天想44 分钟前
vant4+vue3上传一个pdf文件并实现pdf的预览。使用插件pdf.js
开发语言·javascript·pdf·vant
惊鸿一博1 小时前
c++ &&(通用引用)和&(左值引用)区别
开发语言·c++
企鹅不耐热.1 小时前
Scala基础知识6
开发语言·后端·scala