javascript基础修炼(8)——指向FP世界的箭头函数 (3)

或许你已经发现了问题所在,这里的f函数相当于pipeline方法的代理,但这个代理什么额外的动作都没有做,相当于只是在函数调用栈中凭空增加了一层,但是执行了相同的动作。如果你能够理解这一点,就可以得出下面的转化结果:

let f = pipeline;

是不是很神奇?顺便提一下,它的术语叫做point free,当你深入学习【函数式编程】时就会接触到。

3.6 完整的转换代码

我们再进行一些简易的抽象和整理,然后得到完整的流程:

let composeEx = (...args) => (x) => args.reduceRight((pre,cur) =>cur(pre),x); let getValue = (obj) => obj.value; let createTask = (x) => new Task(x); /*goStep执行后得到的函数也满足前面提到的“let f=(x)=>g(x)”的形式,可以将其pointfree化. let goStep = (fn)=>(params)=>composeEx(createTask, fn, getValue)(params); let requireFn2Result = goStep(fn3); */ let requireFn2Result = composeEx(createTask,fn3,getValue); let requireFn1Result = composeEx(createTask,fn2,getValue); let requireInitResult = composeEx(createTask,fn1,getValue); let pipeline = composeEx(requireFn2Result,requireFn1Result,requireInitResult,createTask); let f = pipeline; let y = f(x);

可以看到我们定义完方法后,像搭积木一样把它们组合在一起,就得到了一个可以实现目标功能的函数。

3.7 为什么它看起来变得更复杂了

如果只看上面的示例,的确是这样的,上面的示例只是为了展示函数式编程让代码向着怎样一个方向去变化而已,而并没有展示出函数式编程的优势,这种转变和一个jQuery开发者刚开始使用诸如angular,vue,React框架时感受到的强烈不适感是很相似的,毕竟思想的转变是非常困难的。

面向对象编程写出的代码看起来就像是一个巨大的关系网和逻辑流程图,比如连续读其中10行代码,你或许能够很清晰地看到某个步骤执行前和执行后程序的状态,但是却很难看清整体的业务逻辑流程;而函数式编程正好是相反的,你可以在短短的10行代码中看到整个业务流程,当你想去深究某个具体步骤时,再继续展开,另一方面,关注数据和函数组合可以将你从复杂的this和对象的关系网中解放出来。

四. 两个主角

数据函数【函数式编程】中的两大核心概念,它为我们提供了用数学的眼光看世界的独特视角,同时它也更程序员该有的思维模式——设计程序,而不是仅仅是复现业务逻辑:

程序设计 = 数据结构 + 算法 Vs 函数式编程 = 数据 + 函数

但为了更加安全有效地使用,它们和传统编程中的同名概念相比多了一些限制。

函数Vs纯函数

函数式编程中所传递和使用的函数,被要求为【纯函数】。纯函数需要满足如下两个条件:

只依赖自己的参数

执行过程没有副作用

为什么纯函数只能依赖自己的参数?因为只有这样,我们才不必在对函数进行传递和组合的时候小心翼翼,生怕在某个环节弄丢了this的指向,如果this直接报错还好,如果指向了错误的数据,程序本身在运行时也不会报错,这种情况的调试是非常令人头疼的,除了逐行运行并检查对应数据的状态,几乎没什么高效的方法。面向对象的编程中,我们不得不使用很多bind函数来绑定一个函数的this指向,而纯函数就不存在这样的问题。来看这样两个函数:

var a = 1; function inc(x){ return a + x; } function pureInc(x){ let a = 1; return x + a; }

对于inc这个函数来说,改变外部条件a的值就会造成inc函数对于同样的入参得到不同的结果的情况,换言之在入参确定为3的前提下,每次执行inc(3)得到的结果是不确定的,所以它是不纯的。而pureInc函数就不依赖于外界条件的变化,pureInc(3)无论执行多少次,无论外界参数如何变化,其输出结果都是确定的。

在面向对象的编程中,我们写的函数通常都不是纯函数,因为编程中或多或少都需要在不同的函数中共享一些标记状态的变量,我们更倾向与将其放在更高层的作用域里,通过标识符的右查询会沿作用域链寻找的机制来实现数据共享。

什么是函数的副作用呢?一个函数执行过程对产生了外部可观察的变化那么就说这个函数是有副作用的。最常见的情况就是函数接受一个对象作为参数,但是在函数内部对其进行了修改,javascript中函数在传递对象参数时会将其地址传入调用的函数,所以函数内部所做的修改也会同步反应到函数外部,这种副作用会在函数组合时造成最终数据的不可预测性,因为有关某个对象的函数都有可能得到不确定的输出。

数据Vs不可变数据

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpfxpp.html