JavaScript 中的函数式编程:函数,组合和柯里化,2024年最新2024最新阿里Web前端面经

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Web前端全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip1024c (备注前端)
img

正文

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,PHP,Python等等,你会发现这样的代码你写地最多。这就是问题所在

现在让我们一步一步的解决问题,最后封装成一个看不见 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]

最后

资料过多,篇幅有限

自古成功在尝试。不尝试永远都不会成功。勇敢的尝试是成功的一半。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 10; // 警告:值被改变!

}

console.log(things); // [10, 20, 30, 40]

最后

[外链图片转存中…(img-vWr4GhhW-1713307267055)]

[外链图片转存中…(img-YHGT7lqj-1713307267056)]

资料过多,篇幅有限

自古成功在尝试。不尝试永远都不会成功。勇敢的尝试是成功的一半。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)
[外链图片转存中…(img-gP2YMBIF-1713307267057)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 23
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值