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 分钟前
[react]searchParams转普通对象
开发语言·前端·javascript
信号处理学渣25 分钟前
matlab画图,选择性显示legend标签
开发语言·matlab
红龙创客25 分钟前
某狐畅游24校招-C++开发岗笔试(单选题)
开发语言·c++
jasmine s35 分钟前
Pandas
开发语言·python
biomooc1 小时前
R 语言 | 绘图的文字格式(绘制上标、下标、斜体、文字标注等)
开发语言·r语言
骇客野人1 小时前
【JAVA】JAVA接口公共返回体ResponseData封装
java·开发语言
black^sugar1 小时前
纯前端实现更新检测
开发语言·前端·javascript
404NooFound1 小时前
Python轻量级NoSQL数据库TinyDB
开发语言·python·nosql
用余生去守护2 小时前
python报错系列(16)--pyinstaller ????????
开发语言·python
数据小爬虫@2 小时前
利用Python爬虫快速获取商品历史价格信息
开发语言·爬虫·python