函数式编程 ( Functional Programming ) 是一种以函数为基础的编程方式和代码组织方式,能够带来更好的代码调试及项目维护的优势。本篇主要结合笔者在实际项目开发中的一些应用,简要谈谈函数式编程。 函数在函数式编程中,任何代码可以都是函数,且要求具有返回值,如下示例 1 2 3 4 | var title = "Functional Programming" ;
var saying = "This is not" ;
console.log(saying + title);
|
1 2 3 | var say = title => "This is " + title;
var text = say( "Functional Programming" );
|
纯函数纯函数在这里指函数内外间是“无”关联的。主要有下面两点 1 2 3 | var title = "Functional Programming" ;
var say = ()=> "This is not" + title;
|
1 2 3 | var say = (title)=> "This is " + title;
say( "Functional Programming" );
|
不可变数据(immutable)这里主要是指变量值的不可变。当需要基于原变量值改变时,可通过产生新的变量来确保原变量的不变性,如下 1 2 3 4 | var arr = [ "Functional" , "Programming" ];
arr[0] = "Other" ;
console.log(arr)
|
1 2 3 4 5 6 7 8 9 10 11 | var arr = [ "Functional" , "Programming" ];
var newArr = arr.map(item => {
if (item === "Functional" ){
return "Other" ;
} else {
return item;
}
})
console.log(arr);
console.log(newArr);
|
之所以使用这种不变值,除了更好的函数式编程外,还能够维持线程安全可靠,落地在业务中,实际上也能让代码更加清晰。 设想,如果你定义了一个变量A,A在其他地方被其他人修改了,这样是不方便定位A的当前值的。关于定义多个变量引发的内存等问题,可以通过重用结构或部分引用的方式来减轻,可参考 immutable.js 使用 map, reduce 等数据处理函数强大的 JavaScript 有着越来越多的高能处理数据函数,其中包含了 map、 reduce、 filter 等。 map 能够对原数组中的值进行逐个处理并产生新的数组,一个简单例子 1 2 3 4 5 | var data = [1, 2, 3];
var squares = data.map( (item, index, array) => item * item );
console.log(squares);
console.log(data);
|
reduce 能够对原数组中的各个值进行结合处理,来产生新的值,如下面例子中,previous 代表上一个值,current 代表当前值,reduce 函数可以传入第二个参数作为 previous 初始值,不传时则 previous 初始值为数组中第一个值。 1 2 3 | var sum = [1, 2, 3].reduce( (previous, current, index, array) => previous + current );
console.log(sum);
|
函数柯里化 Currying柯里化 是将多参函数转换成一系列的单参函数。结合下面例子来说明下 1 2 3 | var add = (a, b) => a + b;
add(1, 2);
|
将上面的多参函数进行柯里化,如下 1 2 | var add = a => b => a + b;
|
上面柯里化后的函数调用方式也有所转变,第一次传入一个参数返回了一个函数,再传入参数则完成整体的调用,这也是利用的闭包的特性 1 2 | var add1 = add(1);
add1(2);
|
柯里化后的函数,也可以应用在生产 “ 函数 ” 上,如下示例 1 2 3 4 5 6 7 | var say = title => type => title + " is " + type;
var sayFP = say( "Functional Programming" );
var sayOther = say( "Other Programming" );
sayFP( "good" );
sayOther( "good" );
|
组合函数 compose顾名思义,组合函数是将多个函数进行组合成一个函数。举个例子 1 2 3 4 5 6 | var compose = (fn1, fn2) => (arg) => fn1(fn2(arg));
var a = arg => arg + 'a' ;
var b = arg => arg + 'b' ;
var c = compose(a, b);
c( 'c' );
|
上面示例中,当调用组合函数 c 时,传入的参数会经过 b 函数,接着将 b 函数的返回值作为 a 函数的参数值,从而输出最终结果。 组合函数 c 就像管道一样,将水流( 返回值 )流经各个函数中进行处理。 当想要组合很多函数成一条很长很长的“管道”时,那么显然上面的 compose 函数已经不够用了。下面看看 redux 是怎么做这个 compose 工具函数的。 1 2 3 4 5 6 7 8 9 10 | export default function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg
} else {
const last = funcs[funcs.length - 1]
const rest = funcs.slice(0, -1)
return (...args) => rest.reduceRight((composed, f) => f(composed), last(...args))
}
}
|
代码很简洁,主要利用了递归方式和数组的 reduceRight 方法来处理,reduceRight 跟上边提到的 reduce 方法功能是一样的,不同的是 reduceRight 是从数组的末尾向前逐个处理。就这样,想拼多长的就多长。 以上,便是笔者在项目实践中应用较多的函数式编程内容,如有不妥,请斧正。 附: 一些可供学习函数式编程的内容 转自:joeyguo个人博客 |