JavaScript高阶函数

119 阅读3分钟

如果你正在使用JavaScript, 你应该知道在JavaScript中有函数式编程, 以及JavaScript中的一等公民(First-Class Functions)

函数式编程

函数式是一种编程形式,你可以将函数作为参数传递给其他函数,并将它们作为值返回。 在函数式编程中,我们以函数的形式思考和编程。

高阶函数

JS函数实际上都是指向某一个变量

const test = function(a, b) {}
function test() {}

函数中的参数可以接受变量,那么一个函数就可以接受一个函数作为变量。高阶函数可以理解为:一个函数接受另一个函数作为参数变量的这个函数就是高阶函数
我们在JavaScript中有很多的高阶函数, 常见的高阶函数有:

  • setTimeout, setInterval
  • Array的ES6扩展方法(map, reduce, filter, forEach, every, some)等。
function test(a, b, pow) {
  return pow(a, 2) + pow(b, 2);
}
function pow(x, n) {
  return Math.pow(x, n);
}
//pow作为参数传给test,所以test就是高阶函数
const ret = test(2, 3, pow);  

高阶函数的特点

  • 抽象成完全独立的函数体
  • 高阶函数最大的特点就是便于扩展,易于维护
  • 一个方法执行完之后的行为由高阶函数中的函数参数来进行函数的编写

柯里化(Curry)-函数式编程的思想

柯里化:把变量和方法保存在函数中不销毁;把接收多个参数的函数变换成接收一个单一参数的函数(单一参数为多数中的第一个) 函数柯里化思想:一个JS预处理的思想,降低通用性,提高适用性
例如:

function test(a, b, c) {
  return a + b + c;
}
//我们要让下面的所有执行都能获得一样的结果
test(1, 2, 3);
test(1)(2)(3);
test(1, 2)(3);
test(1)(2, 3);

下面我们开始从简->难开始写些小例子

//实现上面要执行的函数
function curry(fn) {
  const arg1 = Array.from(arguments).slice(1);   //arg1这一层的参数个数不确定
  return function(arg2) {
    const arg2 = arg1.concat(Array.from(arguments));  //arg2这一层的参数个数也不确定,所以我们需要cancat(arg1, arg2)
    return fn.apply(this, arg2);
  }
}
function add(a, b, c, d) {
  return a + b + c + d;
}
const add2 = curry(add, 1, 2);
const ret = curry(3, 4);  //能返回正确的结果为: 10

上面实现的柯里化函数如果按照特定的传参能够得到最终的结果,但是如果我们一共传了3个参数,例如(1,3)(4),这时候就会返回NaN(因为我们少传了一个参数,到add相加的时候undefined + number = NaN),另一方面就是我们现在只返回了一次function, 也不能自己用手 一直写,所以就要用到递归了。
柯里化正确的写法

function curry(fn, len) {
    len = len || fn.length;     //len为fn函数的实参个数  
    const func = function() {
        const arg1 = Array.from(arguments).slice(1);
        return function() {
            const arg2 = arg1.concat(Array.from(arguments));
            return fn.apply(this, arg2);
        }
    }
    return function() {
        const argLen = arguments.length;     //得到非第一次的参数个数
        if(argLen < len) {      //如果当前参数个数小于总的参数,继续递归
            const formatedArr = [fn].concat(Array.from(arguments));
            return curry(func.apply(this, formatedArr), len - argLen);
        } else {        //最后如果参数等于fn的实参个数的话就最后执行fn
            return fn.apply(this, arguments);
        }
    }
}

const add1 = curry(add, 4);
let ret = add1(1, 2, 3)(4);     //ret = 10     
let ret = add1(1)(2, 3, 4);     //ret = 10

** 重点式函数参数的传递 **