JS高阶编程技巧--compose函数

先看代码:

let fn1 = function (x) {
    return x + 10;
};
let fn2 = function (x) {
    return x * 10;
};
let fn3 = function (x) {
    return x / 10;
};

console.log(fn3(fn1(fn2(fn1(6)))));

这是几个简单的运算方法,但想输出的是一个多层函数嵌套的运行结果,即把前一个函数的运行结果赋值给后一个函数,当然我们可以写成一下这样:

let x = fn1(6);
x = fn2(x);
x = fn1(x);
x = fn3(x);

但现在我就想用一个函数解决这种问题,形如:

compose(fn1, fn2, fn1, fn3)(6);

这个compose函数就是这篇文章介绍的——函数调用的扁平化,即把层级嵌套的那种函数调用(一个函数的运行结果当作实参传给下一个函数的这种操作)扁平化,这就是compose函数。

那么下面就是开始实现这个函数:

首先我们看参数,需要给出不确定个数的函数:

function compose(...funcs) {
    //=>funcs:传递的函数集合
}

compose函数执行后跟个(),说明函数执行完再执行一个函数,即函数执行完会返回一个新函数,而且也会给出第一次调用函数时的参数:

function compose(...funcs) {
    //=>funcs:传递的函数集合
    return function proxy(...args) {
      //=>args:第一次调用函数传递的参数集合

    }
}

继续往下进行,我们需要判断给出的函数集合的个数,如果没有给函数,我们只需将后一个的参数返回,如果只给出一个函数,我们只需把后一个的参数赋给这个函数去执行即可:

function compose(...funcs) {
    //=>funcs:传递的函数集合
    return function proxy(...args) {
        //=>args:第一次调用函数传递的参数集合
        let len = funcs.length;
        if (len === 0) {
            //=>一个函数都不需要执行,直接返回ARGS
            return args;
        }
        if (len === 1) {
            //=>只需要执行一个函数,把函数执行,把其结果返回即可
            return funcs[0](...args);
        }

    };
}

如果给出的参数集合是两个及以上,那就是把前一个函数的执行结果赋给后一个函数,说到这,应该会想到一个满足这个需求的数组方法——reduce:

function compose(...funcs) {
    //=>funcs:传递的函数集合
    return function proxy(...args) {
        //=>args:第一次调用函数传递的参数集合
        let len = funcs.length;
        if (len === 0) {
            //=>一个函数都不需要执行,直接返回ARGS
            return args;
        }
        if (len === 1) {
            //=>只需要执行一个函数,把函数执行,把其结果返回即可
            return funcs[0](...args);
        }
        return funcs.reduce((x, y) => {

        });
    };
}

但这里需要注意的是,第一次执行的时候,参数x是个函数,之后再执行的时候x是个函数执行的结果,所以需要进行判断:

function compose(...funcs) {
    //=>funcs:传递的函数集合
    return function proxy(...args) {
        //=>args:第一次调用函数传递的参数集合
        let len = funcs.length;
        if (len === 0) {
            //=>一个函数都不需要执行,直接返回ARGS
            return args;
        }
        if (len === 1) {
            //=>只需要执行一个函数,把函数执行,把其结果返回即可
            return funcs[0](...args);
        }
        return funcs.reduce((x, y) => {
            return typeof x === "function" ? y(x(...args)) : y(x)
        });
    };
}

这样,compose函数完成。

当然,redux源码中的compose.js也可以实现一开始想要的效果:

export default function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }

  if (funcs.length === 1) {
    return funcs[0]
  }

  return funcs.reduce((a, b) => (...args) => a(b(...args)))
}

但它和我们写的compose函数有些不同,它执行的顺序是函数集合中的函数从后往前执行,所以结果也会不同:

compose(fn1, fn2, fn1, fn3)(6)); //=> 用第一个compose执行的结果是17,用redux的执行结果是116

原文地址:https://www.cnblogs.com/ronaldo9ph/p/12323026.html

时间: 2024-10-11 10:33:33

JS高阶编程技巧--compose函数的相关文章

JS高阶编程技巧--惰性函数

在vue.react等框架大量应用之前,我们需要使用jQuery或者原生js来操作dom写代码,在用原生js进行事件绑定时,我们可以应用DOM2级绑定事件的方法,即:元素.addEventListener(),因为兼容性,还有: 元素.attachEvent().所以我们需要封装成一个方法: function emit(element, type, func) { if (element.addEventListener) { element.addEventListener(type, fun

JS高阶编程技巧--柯理化函数

首先看一段代码: let obj = { x: 100 }; function fn(y) { this.x += y; console.log(this); } 现在有一个需求:在1秒后,执行函数fn,并让其this指向obj. 如果写成 setTimeout(fn, 1000); 这么写的话,fn函数中的this是指向window的,而且也没有传递参数. 如果写成 setTimeout(fn(200), 1000); 这么写的话,this指向依然是window,而且相当于立即执行fn函数,并

阿里云王牌架构师杨曦:也谈系统缓存设计误区及高阶使用技巧

阿里云高级解决方案架构师 杨旭世界最大混合云的总架构师,4年前,开始作为双11阿里云技术负责人,负责搭建全球最大的混合云结构,把 "双11"的电商业务和技术场景在阿里云上实现,并保障这个混合云在双11当天能够满足全球客户的购物需求. 正文 相信很多研发同学都有过引入缓存进入到应用架构设计中的经历,本文从几个角度阐述一些选型误区和使用误区以及高阶使用技巧等,供开发者参考. 什么情况下开始考虑缓存? 缓存的主要目的是为了挡一些读多写少的用户请求,且数据在一定时间周期内保持不变,再且业务允许

js 高阶函数 闭包

摘自  https://www.cnblogs.com/bobodeboke/p/5594647.html 建议结合另外一篇关于闭包的文章一起阅读:http://www.cnblogs.com/bobodeboke/p/6127650.html 一.闭包 闭包某种程度上就是函数的内部函数,可以引用外部函数的局部变量.当外部函数退出后,如果内部函数依旧能被访问到,那么内部函数所引用的外部函数的局部变量就也没有消失,该局部变量的生存周期就被延续. 一个经典的例子如下: <script> //thi

Spark函数高阶编程

package com.dtspark.scala.basics /**  * 函数式编程进阶:  * 1,函数和变量一样作为Scala语言的一等公民,函数可以直接赋值给变量:  * 2, 函数更长用的方式是匿名函数,定义的时候只需要说明输入参数的类型和函数体即可,不需要名称,但是如果你  *要使用的话,一般会把这个匿名函数赋值给一个变量(其实是val常量),Spark源码中大量存在这种语法,必须掌握:  * 3, 函数可以作为参数直接传递给函数,这极大的简化的编程的语法,为什么这样说呢?原因非

js高阶函数应用—函数柯里化和反柯里化

在Lambda演算(一套数理逻辑的形式系统,具体我也没深入研究过)中有个小技巧:假如一个函数只能收一个参数,那么这个函数怎么实现加法呢,因为高阶函数是可以当参数传递和返回值的,所以问题就简化为:写一个只有一个参数的函数,而这个函数返回一个带参数的函数,这样就实现了能写两个参数的函数了(具体参见下边代码)--这就是所谓的柯里化(Currying,以逻辑学家Hsakell Curry命名),也可以理解为一种在处理函数过程中的逻辑思维方式. 1 function add(a, b) { 2 retur

浅谈JS高阶函数

引入 我们都知道函数是被设计为执行特定任务的代码块,会在某代码调用它时被执行,获得返回值或者实现其他功能.函数有函数名和参数,而函数参数是当调用函数接收的真实的值. 今天要说的高阶函数的英文为Higher-order function, 高阶函数的高阶是什么意思呢? 定义 至少满足下列一个条件的函数 接收一个或多个函数作为输入 输出一个函数 怎么理解这么个东西呢?引言里说过了,函数实际上都是指向某个变量.既然变量可以是一个向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这

js高阶函数

map()方法定义在JavaScript的Array中,我们调用Array的map()方法,传入我们自己的函数,就得到了一个新的Array作为结果: function pow(x) { return x * x; } var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]; arr.map(pow); // [1, 4, 9, 16, 25, 36, 49, 64, 81] reduce()把一个函数作用在这个Array的[x1, x2, x3...]上,这个函数必须接收两个

js高阶函数filter、map、reduce

1 // 高阶函数 filter/map/reduce 2 3 // filter中的回调函数有一个要求:必须返回一个boolean值, 4 // 当返回true时,函数内部会自动将这次回调的 n 加入到新的数组中 5 // 当返回false时,函数内部会自动过滤掉这次的 n 6 const nums=[10,20,60,94,348,57,24,674,645,44,4] 7 let newNums = nums.filter(function (n){ 8 return n<30 9 })