函数式编程

函数式编程

Javascript的箭头函数

ECMAScript2015引入箭头表达式。箭头函数其实是匿名函数,基本语法如下:

(param1, param2, …, paramN) => { statements }

(param1, param2, …, paramN) => expression

// 等于 : => { return expression; }

// 只有一个参数时,括号才可以不加:

(singleParam) => { statements }

singleParam => { statements }

//如果没有参数,就一定要加括号:

() => { statements }

示例:

1
2
3
4
5
6
7
8
9
10
var simple = a => a > 15 ? 15 : a;
simple(16); // 15
simple(10); // 10

let max = (a, b) => a > b ? a : b;

var arr = [5, 6, 13, 0, 1, 18, 23];
var sum = arr.reduce((a, b) => a + b); //66
var even = arr.filter(v => v % 2 == 0); // [6, 0, 18]
var double = arr.map(v => v * 2); // [10, 12, 26, 0, 36, 46]

有些时候,某些函数在声明的时候就是调用的时候,尤其是函数式编程中,一个函数还对外返回函数的时候。

1
2
3
4
5
6
7
8
9
10
11
function MakePowerFn(power) {
return function PowerFn(base) {
return Math.pow(base, power);
}
}

power3 = MakePowerFn(3); // 制造一个X的3次方的函数
power2 = MakePowerFn(2); // 制造一个X的2次方的函数

console.log(power3(10)); // 10的3次方 1000
console.log(power2(10)); // 10的2次方 100

用箭头函数

1
2
3
4
5
6
7
8
9
10
11
12
13
MakePowerFn = power => {
return base => {
return Math.pow(base, power);
}
}

// 简化
MakePowerFn = power => base => Math.pow(base, power)

// 加上括号
MakePowerFn = (power) => (
(base) => (Math.pow(base, power))
)

匿名函数的递归

函数式编程立志于用函数表达式来消除有状态的函数,以及for/while循环,所以在函数式编程里不应该用for/while循环,而要改用递归(递归的性能很差,所以,一般用尾递归来做优化,也就是把函数的计算状态当参数一层一层往下传递,这样语言的编译器后解释器就需要用函数栈来帮你保存函数的内部变量的状态了)。

递归的代码就是函数自己调用自己,比如求阶乘

1
2
3
function fact(n){
return n == 0 ? 1 : n * fact(n-1);
}

对于匿名函数,可以把匿名函数当成一个参数传给另外一个函数,因为函数的参数有名字,所以就可以调用自己了。

1
2
3
4
5
6
function combinator(func) {
func(func);
}

// 箭头函数式的匿名函数
func) => (func(func))

阶乘代码重构

1
2
3
4
5
6
7
8
9
10
11
12
13
funtion fact(func, n){
return n == 0 ? 1: n * func(func, n-1);
}

// 匿名函数版
var fact = (func, n) => (n == 0 ? 1 : func(func, n-1));
fact(fact, 5)

// 函数体声明时调用自己
func, x) => func(func, x)(
(func, n) => ( n ==0 ? 1 : n * func(func, n-1)), // 第一个调用参数
5 // 第二个调用参数
);

动态高级函数的递归

递归版高阶函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
HighOrderFact = function(func){
return function(n){
return n == 0 ? 1 : func(func)(n-1);
};
}

// 需要一个函数做参数,然后返回这个函数的递归版本
fact = HighOrderFact(HighOrderFact);
fact(5);

HighOrderFact(HighOrderFact)(5);

fact = function(hifunc) {
return hifunc(hifunc);
}(
// 调用参数是一个函数
function(func){
return function(n){
return n == 0 ? 1 : n * func(func)(n-1);
};
}
);
// 调用
fact(5);

// 箭头函数重构
fact = (highfunc => highfunc(highfunc)) (
func => n => n == 0 ? 1 : n * func(func)(n-1)
);

重构之前的程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
 // 查找数组正常版本
function find(x, y) {
for(let i = 0; i< x.length; i++){
if(x[i] == y) return i;
}
return null;
}

// 干掉for,搞成递归版本
funcion find(x, y, i=0){
if( i >= x.length) return null;
if( x[i] == y) return i;
return find(x, y, i+1);
}

// 继续重构 带实参的匿名函数版本
((func, x, y, i) => func(func, x,y i)) ( // 函数体
(func, x, y, i=0) => (
i>= x.length ? null :
x[i] == y ? i : func(func, x, y, i+1)
), // 第一个调用参数
arr, // 第二个调用参数
2 // 第三个调用参数
)
// 引入高级函数,去除实参

const find = (highfunc => highfunc(highfunc))(
func => (x, y, i =0 ) => (
i >= x.length ? null :
x[i] == y ? i : func(func)(x, y, i+1)
)
)
;

可以参考以下两篇文章

文章目录
  1. 1. 函数式编程
    1. 1.1. Javascript的箭头函数
    2. 1.2. 匿名函数的递归
    3. 1.3. 动态高级函数的递归
    4. 1.4. 重构之前的程序
,
Fork me on GitHub