iis服务器助手广告广告
返回顶部
首页 > 资讯 > 前端开发 > html >JavaScript中的高阶函数和柯里化以及组合函数是怎样的
  • 933
分享到

JavaScript中的高阶函数和柯里化以及组合函数是怎样的

2024-04-02 19:04:59 933人浏览 泡泡鱼
摘要

这期内容当中小编将会给大家带来有关javascript中的高阶函数和柯里化以及组合函数是怎样的,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。面向对象编程和函数式编程是两种

这期内容当中小编将会给大家带来有关javascript中的高阶函数和柯里化以及组合函数是怎样的,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。

面向对象编程函数式编程是两种非常不同的编程范式,它们有自己的规则和优缺点。

但是,JavaScript 并没有一直遵循一个规则,而是正好处于这两个规则的中间,它提供了普通OOP语言的一些方面,比如类、对象、继承等等。但与此同时,它还为你提供了函数编程的一些概念,比如高阶函数以及组合它们的能力。

高阶函数

我们行人人三个概念中最重要的一个开始:高阶函数。

高阶函数意味着函数不仅仅是一个可以从代码中定义和调用,实际上,你可以将它们用作可分配的实体。如果你使用过一些JavaScript,那么这并不奇怪。将匿名函数分配给常量,这样的事情非常常见。

const adder = (a, b) => {
  return a + b
}

上述逻辑在许多其他语言中是无效的,能够像分配整数一样分配函数是一个非常有用的工具,实际上,本文涵盖的大多数主题都是该函数的副产品。

高阶函数的好处:封装行为

有了高阶函数,我们不仅可以像上面那样分配函数,还可以在函数调用时将它们作为参数传递。这为创建一常动态的代码基打开了大门,在这个代码基础上,可以直接将复杂行为作为参数传递来重用它。

想象一下,在纯面向对象的环境中工作,你想扩展类的功能,以完成任务。 在这种情况下,你可能会使用继承,方法是将该实现逻辑封装在一个抽象类中,然后将其扩展为一组实现类。 这是一种完美的 OOP 行为,并且行之有效,我们:

  • 创建了一个抽象结构来封装我们的可重用逻辑

  • 创建了二级构造

  • 我们重用的原有的类,并扩展了它

现在,我们想要的是重用逻辑,我们可以简单地将可重用逻辑提取到函数中,然后将该函数作为参数传递给任何其他函数,这种方法,可以少省去一些创建“样板”过程,因为,我们只是在创建函数。

下面的代码显示了如何在 OOP 中重用程序逻辑。

//Encapsulated behavior封装行为stract class LogFORMatter {
  
  format(msg) {
    return Date.now() + "::" + msg
  } 
}

//重用行为
class ConsoleLogger extends LogFormatter {
  
  log(msg) {
    console.log(this.format(msg))
  }  
}

class FileLogger extends LogFormatter {

  log(msg) {
    writeToFileSync(this.logFile, this.format(msg))
  }
}

第二个示是将逻辑提取到函数中,我们可以混合匹配轻松创建所需的内容。 你可以继续添加更多格式和编写功能,然后只需将它们与一行代码混合在一起即可:

// 泛型行为抽象
function format(msg) {
  return Date.now() + "::" + msg
}

function consoleWriter(msg) {
  console.log(msg)
}

function fileWriter(msg) {
  let logFile = "logfile.log"
  writeToFileSync(logFile, msg)
}

function logger(output, format) {
  return msg => {
    output(format(msg))
  }
}
// 通过组合函数来使用它
const consoleLogger = logger(consoleWriter, format)
const fileLogger = logger(fileWriter, format)

这两种方法都有优点,而且都非常有效,没有谁最优。这里只是展示这种方法的灵活性,我们有能力通过 行为(即函数)作为参数,就好像它们是基本类型(如整数或字符串)一样。

高阶函数的好处:简洁代码

对于这个好处,一个很好的例子就是Array方法,例如forEachmapreduce等等。 在非函数式编程语言(例如C)中,对数组元素进行迭代并对其进行转换需要使用for循环或某些其他循环结构。 这就要求我们以指定方式编写代码,就是需求描述循环发生的过程。

let myArray = [1,2,3,4]
let transformedArray = []

for(let i = 0; i < myArray.length; i++) {
  transformedArray.push(myArray[i] * 2) 
}

上面的代码主要做了:

  • 声明一个新变量i,该变量将用作myArray索引,其值的范围为0myArray的长度

  • 对于i的每个值,将myArray的值在i的位置相乘,并将其添加到transformedArray数组中。

这种方法很有效,而且相对容易理解,然而,这种逻辑的复杂性会随着项目的复杂程度上升而上升,认知负荷也会随之增加。但是,像下面这种方式就更容易阅读:

const double = x => x * 2;

let myArray = [1,2,3,4];
let transformedArray = myArray.map(double);

与第一种方式相比,这种方式更容易阅读,而且由于逻辑隐藏在两个函数(mapdouble)中,因此你不必担心了解它们的工作原理。 你也可以在第一个示例中将乘法逻辑隐藏在函数内部,但是遍历逻辑必须存在,这就增加了一些不必要的阅读阻碍。

柯里化

函数柯里化是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。我们来看个例子:

function adder(a, b) {
  return a + b
}

// 变成
const add10 = x => adder(a, 10)

现在,如果你要做的就是将10添加到一系列值中,则可以调用add10而不是每次都使用相同的第二个参数调用adder。 这个事例看起来比较蠢,但它是体现了 柯里化 的理想。

你可以将柯里化视为函数式编程的继承,然后按照这种思路再回到logger的示例,可以得到以下内容:

function log(msg, msgPrefix, output) {
  output(msgPrefix + msg)
} 

function consoleOutput(msg) {
  console.log(msg)
}

function fileOutput(msg) {
  let filename = "mylogs.log"
  writeFileSync(msg, filename)
}

const logger = msg => log(msg, ">>", consoleOutput);
const fileLogger = msg => log(msg, "::", fileOutput);

log的函数需要三个参数,而我们将其引入仅需要一个参数的专用版本中,因为其他两个参数已由我们选择。

注意,这里将log函数视为抽象类,只是因为在我的示例中,不想直接使用它,但是这样做是没有限制的,因为这只是一个普通的函数。 如果我们使用的是类,则将无法直接实例化它。

组合函数

函数组合就是组合两到多个函数来生成一个新函数的过程。将函数组合在一起,就像将一连串管道扣合在一起,让数据流过一样。

在计算机科学中,函数组合是将简单函数组合成更复杂函数的一种行为或机制。就像数学中通常的函数组成一样,每个函数的结果作为下一个函数的参数传递,而最后一个函数的结果是整个函数的结果

这是来自维基百科的函数组合的定义,粗体部分是比较关键的部分。使用柯里化时,就没有该限制,我们可以轻松使用预设的函数参数。

代码重用听起来很棒,但是实现起来很难。如果代码业务性过于具体,就很难重用它。如时代码太过通用简单,又很少人使用。所以我们需要平衡两者,一种制作更小的、可重用的部件的方法,我们可以将其作为构建块来构建更复杂的功能。

在函数式编程中,函数是我们的构建块。每个函数都有各自的功能,然后我们把需要的功能(函数)组合起来完成我们的需求,这种方式有点像乐高的积木,在编程中我们称为 组合函数。

看下以下两个函数:

var add10 = function(value) {
    return value + 10;
};
var mult5 = function(value) {
    return value * 5;
};

上面写法有点冗长了,我们用箭头函数改写一下:

var add10 = value => value + 10;
var mult5 = value => value * 5;

现在我们需要有个函数将传入的参数先加上 10 ,然后在乘以 5, 如下:

现在我们需要有个函数将传入的参数先加上 10 ,然后在乘以 5, 如下:

var mult5AfterAdd10 = value => 5 * (value + 10)

尽管这是一个非常简单的例子,但仍然不想从头编写这个函数。首先,这里可能会犯一个错误,比如忘记括号。第二,我们已经有了一个加 10 的函数  add10 和一个乘以 5 的函数 mult5 ,所以这里我们就在写已经重复的代码了。

使用函数 add10mult5 来重构 mult5AfterAdd10

var mult5AfterAdd10 = value => mult5(add10(value));

我们只是使用现有的函数来创建 mult5AfterAdd10,但是还有更好的方法。

在数学中, f ∘ g 是函数组合,叫作“f 由 g 组合”,或者更常见的是 “f after g”。 因此 (f ∘ g)(x) 等效于f(g(x)) 表示调用 g 之后调用 f

在我们的例子中,我们有 mult5 ∘ add10 或 “add10 after mult5”,因此我们的函数的名称叫做 mult5AfterAdd10。由于Javascript本身不做函数组合,看看 Elm 是怎么写的:

add10 value =
    value + 10
mult5 value =
    value * 5
mult5AfterAdd10 value =
    (mult5 << add10) value

Elm 中 << 表示使用组合函数,在上例中 value 传给函数 add10 然后将其结果传递给 mult5。还可以这样组合任意多个函数:

f x =
   (g << h << s << r << t) x

这里 x 传递给函数 t,函数 t 的结果传递给 r,函数 t 的结果传递给 s,以此类推。在Javascript中做类似的事情,它看起来会像 g(h(s(r(t(x))))),一个括号噩梦。

常见的函数式函数(Functional Function)

函数式语言中3个常见的函数:Map,Filter,Reduce

如下JavaScript代码:

 for (var i = 0; i < something.length; ++i) {
    // do stuff
 }

这段代码存在一个很大的问题,但不是bug。问题在于它有很多重复代码(boilerplate code)。如果你用命令式语言来编程,比如Java,C#,JavaScript,PHPpython等等,你会发现这样的代码你写地最多。这就是问题所在

现在让我们一步一步的解决问题,最后封装成一个看不见 for 语法函数:

先用名为 things 的数组来修改上述代码:

var things = [1, 2, 3, 4];
for (var i = 0; i < things.length; ++i) {
    things[i] = things[i] * 10; // 警告:值被改变!
}
console.log(things); // [10, 20, 30, 40]

这样做法很不对,数值被改变了!

在重新修改一次:

var things = [1, 2, 3, 4];
var newThings = [];
for (var i = 0; i < things.length; ++i) {
    newThings[i] = things[i] * 10;
}
console.log(newThings); // [10, 20, 30, 40]

这里没有修改things数值,但却却修改了newThings。暂时先不管这个,毕竟我们现在用的是 JavaScript。一旦使用函数式语言,任何东西都是不可变的。

现在将代码封装成一个函数,我们将其命名为 map,因为这个函数的功能就是将一个数组的每个值映射(map)到新数组的一个新值。

var map = (f, array) => {
    var newArray = [];
    for (var i = 0; i < array.length; ++i) {
        newArray[i] = f(array[i]);
    }
    return newArray;
};

函数 f 作为参数传入,那么函数 map 可以对 array 数组的每项进行任意的操作。

现在使用 map 重写之前的代码:

var things = [1, 2, 3, 4];
var newThings = map(v => v * 10, things);

这里没有 for 循环!而且代码更具可读性,也更易分析。

现在让我们写另一个常见的函数来过滤数组中的元素:

var filter = (pred, array) => {
    var newArray = [];
for (var i = 0; i < array.length; ++i) {
        if (pred(array[i]))
            newArray[newArray.length] = array[i];
    }
    return newArray;
};

当某些项需要被保留的时候,断言函数 pred 返回TRUE,否则返回FALSE。

使用过滤器过滤奇数:

var isOdd = x => x % 2 !== 0;
var numbers = [1, 2, 3, 4, 5];
var oddNumbers = filter(isOdd, numbers);
console.log(oddNumbers); // [1, 3, 5]

比起用 for 循环的手动编程,filter 函数简单多了。最后一个常见函数叫reduce。通常这个函数用来将一个数列归约(reduce)成一个数值,但事实上它能做很多事情。

在函数式语言中,这个函数称为 fold

var reduce = (f, start, array) => {
    var acc = start;
    for (var i = 0; i < array.length; ++i)
        acc = f(array[i], acc); // f() 有2个参数
    return acc;
});

reduce函数接受一个归约函数 f,一个初始值 start,以及一个数组 array

这三个函数,map,filter,reduce能让我们绕过for循环这种重复的方式,对数组做一些常见的操作。但在函数式语言中只有递归没有循环,这三个函数就更有用了。附带提一句,在函数式语言中,递归函数不仅非常有用,还必不可少。

上述就是小编为大家分享的JavaScript中的高阶函数和柯里化以及组合函数是怎样的了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注编程网html频道。

--结束END--

本文标题: JavaScript中的高阶函数和柯里化以及组合函数是怎样的

本文链接: https://www.lsjlt.com/news/81889.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • JavaScript中的高阶函数和柯里化以及组合函数是怎样的
    这期内容当中小编将会给大家带来有关JavaScript中的高阶函数和柯里化以及组合函数是怎样的,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。面向对象编程和函数式编程是两种...
    99+
    2024-04-02
  • JavaScript中的函数式编程函数和组合以及柯里化是怎样的
    JavaScript中的函数式编程函数和组合以及柯里化是怎样的,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。面向对象编程和函数式编程是两种非常...
    99+
    2024-04-02
  • 怎样用Javascript实现函数柯里化与反柯里化
    函数柯里化(黑人问号脸)???Currying(黑人问号脸)???妥妥的中式翻译既视感;下面来一起看看究竟什么是函数柯里化: 维基百科的解释是:把接收多个参数的函数变换成接收一个单一...
    99+
    2024-04-02
  • 从柯里化分析JavaScript重要的高阶函数实例
    目录前情回顾百变柯里化缓存传参缓存判断缓存计算缓存函数防抖与节流lodash 高阶函数结语前情回顾 我们在前篇 《✨从历史讲起,JavaScript 基因里写着函数式编程》 讲到了 ...
    99+
    2022-11-13
    JavaScript 柯里化高阶函数 JavaScript 高阶函数
  • JavaScript中的函数柯里化怎么使用
    这篇“JavaScript中的函数柯里化怎么使用”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“JavaScript中的函数柯...
    99+
    2023-07-06
  • JavaScript中函数柯里化的原理是什么
    今天就跟大家聊聊有关JavaScript中函数柯里化的原理是什么,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。柯里化是这样的一个转换过程,把接受多个...
    99+
    2024-04-02
  • JavaScript 中怎么实现柯里化函数
    本篇文章为大家展示了JavaScript 中怎么实现柯里化函数,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。阶段1现在有一个加法函数:function a...
    99+
    2024-04-02
  • JavaScript 闭包与高阶函数是怎样的
    JavaScript 闭包与高阶函数是怎样的,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。「JavaScript 中,函数是一等公民」,在各种...
    99+
    2024-04-02
  • 深入了解JavaScript中的函数柯里化
    目录一、参数复用二、延迟执行三、部分应用四、函数组合JavaScript函数柯里化是一种将接受多个参数的函数转换为一系列接受单个参数的函数的技术。这种技术可以让我们更方便地创建可复用...
    99+
    2023-05-16
    JavaScript函数柯里化 JavaScript 柯里化
  • JavaScript函数柯里化的示例分析
    这篇文章将为大家详细讲解有关JavaScript函数柯里化的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。函数柯里化使用方法:柯里化是函数式编程的一个重要技巧,将使用多个参数的一个函数转换成一系列...
    99+
    2023-06-27
  • JavaScript中函数进阶是怎样现进行的
    JavaScript中函数进阶是怎样现进行的,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。全局作用域· 全局作用域是最大的作用域·&...
    99+
    2024-04-02
  • js柯里化函数的好处是什么
    本篇内容介绍了“js柯里化函数的好处是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!好处说明可以把函数式编程变得简洁,没有冗余。尽管有多...
    99+
    2023-06-20
  • javascript高阶函数指的是什么
    这篇文章主要介绍了javascript高阶函数指的是什么,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。说明可以将函数作为参数传递给另一个函数。将函数作为另一个函数的返回结果。...
    99+
    2023-06-20
  • 详解Python中的普通函数和高阶函数
    目录什么是函数函数的嵌套调用高阶函数我们思考一下计算圆形和方形的面积为何高阶函数能够降低维度总结什么是函数 每个语言都有函数,甚至大家用的Excel里面也有函数,我们以前学习的数学也...
    99+
    2024-04-02
  • JavaScript中常见的高阶函数总结
    目录前言map函数reduce函数filter函数sortevery方法find方法findIndex方法foreach方法总结前言 一个函数可以接受另一个函数作为参数,就把这个函数...
    99+
    2024-04-02
  • JavaScript数组对象高阶函数reduce的妙用详解
    目录reduce 是 JavaScript 数组对象上的一个高阶函数计算数组的平均数求数组的最大值求数组的最小值数组去重计算数组中每个元素出现的次数实现数组分组计算数组中连续递增数字...
    99+
    2023-05-16
    JavaScript数组对象reduce JavaScript高阶函数reduce
  • web开发中函数柯里化的示例分析
    这篇文章给大家分享的是有关web开发中函数柯里化的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。前言函数柯里化就是将多参简化为单参数的一种技术方式,其最终支持的是方法的连...
    99+
    2024-04-02
  • 在JavaScript中使用高阶函数的方法
    目录JavaScript将函数视为一等公民高阶函数接收函数作为参数代码可重用性返回函数高阶函数模板正在使用高阶函数总结将另一个函数作为参数的函数,或者定义一个函数作为返回值的函数,被...
    99+
    2024-04-02
  • 8个JavaScript中高阶函数的运用分享
    目录函数作为参数传递函数作为返回值函数柯里化函数组合面向切面编程函数式编程闭包复杂的例子函数作为参数传递 高阶函数可以接受一个或多个函数作为参数,这些函数可以在高阶函数中被调用,实现...
    99+
    2023-05-16
    JavaScript高阶函数运用 JavaScript高阶函数
  • SQL分组函数group by和聚合函数COUNT、MAX、MIN、AVG、SUM是什么以及怎么用
    本篇内容主要讲解“SQL分组函数group by和聚合函数COUNT、MAX、MIN、AVG、SUM是什么/用法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学...
    99+
    2024-04-02
软考高级职称资格查询
推荐阅读
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作