JavaScript函数式编程与函数柯里化(进阶一)

最近在学习JavaScript函数式编程,浏览了知乎前端大神的教程,故做简

单笔记。

/* ------------------------------------------------------------------------------------------------------------ 
    函数的纯与不纯
*/
//对于相同的输入,永远会得到相同的输出,而且没有任何可观察的副作用,也不依赖外部环境的状态
//eg:
var arr = [1, 2, 3, 4, 5]
//array.slice是纯函数,没有副作用,对于固定的输入,输出总是固定的
var xs = arr.slice(0, 3)   //[1,2,3]
console.log(xs)     //[1,2,3]   
var xs2 = arr.slice(0, 3)
console.log(xs2)    //[1,2,3]
/*输出是一样的*/

//array.splice是不纯的,它有副作用,对于固定的输入,输出是不固定的。
arr.splice(0, 3)
console.log(arr)    //[4,5]
arr.splice(0, 3)
console.log(arr)    //[]
/*输出不固定,会随时变化*/

// 在函数式编程序,需要的是slice这样的纯函数,而不是splice这种调用后会将数据弄乱的函数
// 为什么函数式编程会排斥不纯的函数呢? eg:
var min = 18;
//不纯
var checkage = age => age > min; 
// -- > var checkage = function(age){return age>min}
console.log(checkage(20))
//纯
var checkage = age => age > 18;
console.log(checkage(20))
//在不纯的版本中,checkage这个函数的行为不仅取决于输入的参数age,还取决于一个外部的变量Min,换句话说,这个函数
//的行为需要由外部系统环境决定,对于大型系统来说,这种对于外部状态的依赖是造成系统复杂性大大提高的主要原因。
//可以注意到,纯的checkage把关键字18硬编在函数内部,拓展性较差,我们可以在后面的柯里化中看到如何优雅的函数式解决这种问题
//纯函数可以有效降低系统复杂度,而却还有可缓存性

/* ------------------------------------------------------------------------------------------------------------ 
    函数的柯里化
*/
/*
    函数的柯里化(curry)的定义很简单,传递给函数一部分参数来调用他,让他返回一个函数去处理剩下的参数
    比如说对于加法函数var add = (x,y) => x+y 可以进行柯里化: 
*/
//es5
var add = function (x) { 
    return function (y) { 
        return x+y
    }
}
//es6 纯正的函数式编程写法
var add = x => (y => x + y);
var add2 = add(2)
console.log(add2(2))        //4
var add200 = add(200)
console.log(add200(200))    //400
//将checkage函数柯里化
//es5
var checkage = function (min) {
    return function (age) {
        return age > min
     }
}
var checkage = min => (age => age > min);
var checkage18 = checkage(18)
console.log(checkage18(20)) //true
//实际上柯里化是一种预加载函数的方法,通过传递较少的参数,得到一个已经记住了这些参数
//的新函数,某种意义上讲,这是一种对参数的“缓存”,是一种非常高效的编写函数的方法:
/*
import { curry } from 'lodash';

//首先柯里化两个纯函数
var match = curry((reg, str) => str.match(reg));
// --> var match = function curry(reg,str){ return str.match(reg) }
var filter = curry((f, arr) => arr.filter(f));

//判断字符串里有没有空格
var haveSpace = match(/\s+/g);

haveSpace("ffffffff");
//=>null

haveSpace("a b");
//=>[" "]

filter(haveSpace, ["abcdefg", "Hello World"]);
//=>["Hello world"]
*/
/* ------------------------------------------------------------------------------------------------------------ 
    函数组合
*/
//学会了使用纯函数以及如何把它柯里化以后,我们很容易写出包菜式代码:
// h(g(f(s)))
// 这是一种不优雅的函数式代码,为了解决函数嵌套问题,我们要用到函数组合
//两个函数组合:
var compose = function (f, g) {
    return function (x) {
        return f(g(x))
    }
}
//或者
var compose = (f, g) => (x => f(g(x)));
var add1 = x => x + 1;
var mul5 = x => x * 5;
var res = compose(mul5, add1)(2);
console.log(res)    //15
/*
解析:
add1 : x = function (x) {return x+1}
mul5 : x = function (x) {return x*5}
内部双调用
f(g(x)) == > f(g(2)) == > f(3) == > return 3*5
}
*/
/*定义的compose就像双面胶,可以把任意两个函数结合到一起,可以拓展为三个,甚至N个*/
var first = arr => arr[0];
var reverse = arr => arr.reverse;
var last = compose(first, reverse);
last([1, 2, 3, 4, 5])
console.log(last([1, 2, 3, 4, 5]))      //5
// last = > compose(f(g(x)))
// -->  
/*  内部详解:
    compose(  
        f => function(arr){return arr[0]}
        g => function(arr){return arr.reverse}
        x => [1,2,3,4,5]
        g(x)=>[5,4,3,2,1]
        f(g(x))=>5
        return f(g(x)) = > return 5
    )
    last => compose(first,reverse) => 5
    var last = function compose(fisrt,reverse){.....}
*/
var str2 = "Hello"
var strc = str2 => str2.concat("???")
console.log(strc(str2))
//仿写:   查询传入的字符串中是否存在H
var one = str => str.concat("!");
var two = str => str.includes('H');
var strLast = compose(two, one)
strLast("Hello World")
console.log(strLast("Hello World")) //true

参考:知乎:Starkwang

https://zhuanlan.zhihu.com/p/21714695

猜你喜欢

转载自blog.csdn.net/weixin_41564885/article/details/83338535