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]
相关推荐
无尽的大道3 分钟前
Java字符串深度解析:String的实现、常量池与性能优化
java·开发语言·性能优化
爱吃生蚝的于勒7 分钟前
深入学习指针(5)!!!!!!!!!!!!!!!
c语言·开发语言·数据结构·学习·计算机网络·算法
binishuaio16 分钟前
Java 第11天 (git版本控制器基础用法)
java·开发语言·git
zz.YE18 分钟前
【Java SE】StringBuffer
java·开发语言
就是有点傻22 分钟前
WPF中的依赖属性
开发语言·wpf
洋24031 分钟前
C语言常用标准库函数
c语言·开发语言
进击的六角龙32 分钟前
Python中处理Excel的基本概念(如工作簿、工作表等)
开发语言·python·excel
wrx繁星点点33 分钟前
状态模式(State Pattern)详解
java·开发语言·ui·设计模式·状态模式
熊的猫41 分钟前
JS 中的类型 & 类型判断 & 类型转换
前端·javascript·vue.js·chrome·react.js·前端框架·node.js
NoneCoder1 小时前
Java企业级开发系列(1)
java·开发语言·spring·团队开发·开发