欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

偏函数、高阶函数、柯里化、匿名函数

程序员文章站 2023-10-17 12:21:18
好久没写博客,从一道题目开始吧 实现一个sum函数,支持sum(1,2)和sum(1)(2)两种调用方式 说实在的,没啥难的,很简单写出来 或者用ES6的展开操作符,或者是arguments 考察的内容其实就是函数作为返回值,简单涉及到了闭包,还有arguments的判断,ES6展开操作符的剩余语法 ......

好久没写博客,从一道题目开始吧

实现一个sum函数,支持sum(1,2)和sum(1)(2)两种调用方式

说实在的,没啥难的,很简单写出来

function sum(a, b) {
  if (b) {
      return a + b;
  }   
  return (b) => a+b; 
}

或者用es6的展开操作符,或者是arguments

function sum(...args) {
  if (args.length === 2) {
      return args[0] + args[1];
  } 
  if (args.length === 1) {
      return (b) => b + args[0]
  }   
}

考察的内容其实就是函数作为返回值,简单涉及到了闭包,还有arguments的判断,es6展开操作符的剩余语法。然后可以继续发散,es6熟不熟啊,闭包理解到不到位啊,arguments是不是数组,怎么转成数组……

不写了,不写了,展开能问的太多了。今天主要的目的是写一写函数相关,解释一下那些常见的概念:偏函数、高阶函数、柯里化、匿名函数。

偏函数

偏函数(partial application),wiki上解释

in computer science,partial application(orpartial function application) refers to the process of fixing a number of arguments to a function, producing another function of smaller arity.

大概意思,偏函数会固定一些参数,产生更少参数的函数。

改一下上面的题目:

实现一个sum函数,可以支持固定一个参数的的调用方式;如

var sum1 = sum(1);

sum1(2) // 3

function sum(base) {
    return (num) => base + num;
}
var sum1 = sum(1);

或者使用bind

function sum(a, b) {
    return a + b;
}
var sum1 = sum.bind(null, 1);

这里可以引申出bind的用法,bind和call的区别,call和apply的区别。就不多赘述了。之前写过一篇博客。

高阶函数

在数学和计算机科学中,高阶函数是至少满足下列一个条件的函数: 接受一个或多个函数作为输入 输出一个函数

wiki链接

可以这么理解,如果可以接受函数作为入参和出参的,可以认为支持高阶函数。js中,函数是一等公民,各种高阶函数随处可见,很容易写一个例子:

const print = console.log;
const foo = (a , b, printfn) => a + b;

foo(1, 2, print);

说个题外话,有这样一道题目:

[1,2,3].map(parseint)

我感觉这个题目有点考api记忆了,不过如果熟练的话也就还好。map是一个高阶函数,接受一个函数作为参数,他会给入参函数传入两个值,item和index。parseint接受两个参数,数值和进制。也就是执行

parseint(1, 0);
parseint(2, 1);
parseint(3, 2);

答案[1, nan, nan]我就不多说了。

柯里化

在计算机科学中,柯里化(英语:currying),又译为卡瑞化或加里化,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

wiki链接

大概定义一下,可以认为curry之后的函数,可以接受一个参数,之后返回一个接受剩余参数的函数。

期望可以这么执行:

var add = curry((a, b) => a + b);

add(1, 2); // 可以正常运行
var add1 = add(1);
add1(2); // 也可以这么使用

可以发现,这不就是上面的题目吗?当然,稍有不同的地方在于,这里是通过curry把一个正常函数curry化。我们也来实现一个。

function curry (fn) {
    return (...args) => {
       if (args.length === fn.length) {
          return fn.apply(null, args); 
       }
       return fn.bind(null, args[0])
    }
}

很明显,上面用到了偏函数的实现去做了curry,也可以不使用bind,在使用别的方法之前,加一些限定条件。

上面的curry简单处理了一个参数的情况,我们希望curry更智能一些,假设函数有10个参数,如果传了5个,又传了3个,又传了2个,只有最后一次才会返回结果。

// 为了使用递归,写了一个helper
function helper (fn, ...args) {
    if (args.length === fn.length) {
        return fn.apply(null, args);
    }
    return (...argsmore) => createfn(fn, ...args, ...argsmore);
}

function curry (fn) {
    return (...args) => createfn(fn, ...args);
}

多说一个概念,thunk,阮一峰老师在他的博客里介绍过thunk 函数的含义和用法,大家可以看一下,其实也就是curry的一处用法。

匿名函数

在计算机编程中,匿名函数(英语:anonymous function)是指一类无需定义标识符(函数名)的函数子程序,普遍存在于多种编程语言中。

wiki

匿名函数相对命名函数而言,就是一些一次性使用的场景下,比如一些事件处理函数,可能只执行一次,可以使用匿名函数。

这个概念经常用,举个例子。

[1,2,3].map((item, index) => `item ${index}: ${item}`);

匿名函数的概念很简单,上面写的箭头函数容易考察一些this指向的问题。

比如为什么箭头函数不能使用new,怎么做到绑定this的。

这个问题,我打算留到下一篇写。嘿嘿嘿