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]
相关推荐
linhhanpy5 分钟前
自制操作系统(九、操作系统完整实现)
c语言·开发语言·汇编·c++·操作系统·自制操作系统
ACALJJ325 分钟前
STL整理
开发语言·c++
豆本-豆豆奶8 分钟前
最全面的Python重点知识汇总,建议收藏!
开发语言·数据库·python·oracle
Bosenya1211 分钟前
【信号处理】绘制IQ信号时域图、星座图、功率谱
开发语言·python·信号处理
monkey_meng12 分钟前
【Rust Crate之Actix Web(一)】
开发语言·后端·rust
拼图20920 分钟前
Vue.js开发基础——数据绑定/响应式数据绑定
前端·javascript·vue.js
刘志辉25 分钟前
vue反向代理配置及宝塔配置
前端·javascript·vue.js
AI原吾29 分钟前
探索PyAV:Python中的多媒体处理利器
开发语言·python·ai·pyav
oliveira-time39 分钟前
爬虫学习8
开发语言·javascript·爬虫·python·算法
矛取矛求1 小时前
string接口的深度理解(内附思维导图)
c语言·开发语言·c++·接口·string