博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JavaScript函数式编程之pointfree与声明式编程
阅读量:6212 次
发布时间:2019-06-21

本文共 5088 字,大约阅读时间需要 16 分钟。

函数式编程中的pointfree的意思就是“无参”或“无值”,pointfree style是一种编程范式,也作tacit programming,就是“无参编程”的意思了。什么是“无参编程”?

// 这就是有参的,因为有wordvar snakeCase = word => word.toLowerCase().replace(/\s+/ig, '_');// 这是pointfreevar snakeCase = compose(replace(/\s+/ig, '_'), toLowerCase);

从另一个角度看,有参的函数的目的是得到一个数据,而pointfree的函数的目的是得到另一个函数。

所以,如下的方程,虽然也有参,也可以认为是pointfree的。

const titlesForYear = year =>  pipe(    filter(publishedInYear(year)),    map(book => book.title)  )

那这pointfree有什么用?

它可以让我们把注意力集中在函数上,参数命名的麻烦肯定是省了,代码也更简洁优雅。
需要注意的是,一个pointfree的函数可能是由众多非pointfree的函数组成的,也就是说底层的基础函数大都是有参的,pointfree体现在用基础函数组合而成的高级函数上。如果我们使用函数式编程的工具,如ramda,这些基础函数大都已经被写好了,这样我们去写pointfree的代码就很容易了。

什么是声明式编程?它区别于命令式编程

// 命令式var words = [];for (i = 0; i < otherWords.length; i++) {  words.push(otherWords[i].word);}// 声明式var words = otherWords.map(function(ele){ return ele.word; });

容易看出,命令式的代码,我们不但要去遍历,还要关注如何遍历。而声明式的就容易很多,可以节省我们的注意力,代码也更加简洁。

其他的命令式的写法有:使用ifelse进行的条件判断,使用算数运算符进行的算数运算,使用比较运算符进行的比较运算和使用逻辑运算符进行的逻辑运算。

至于那些说“虽然如此,但使用命令式循环速度要快很多”的人,我建议你们先去学学 JIT 优化代码的相关知识。这里有一个 ,可能会对你有帮助。

需要注意的是,要实现这种声明式的编程,首先我们要有这个map方法,这一点与pointfree相同,都是需要我们先对常用的操作做一次封装,而这些常用的操作本身还是命令式的。

pointfree的声明式代码是函数式编程应该有的样子。

最后用一个来自Scott Sauyet的文章中的例子,使用的函数式工具是ramda。下面的代码不需要一句一句的看,大概体会一下就可以了。

一组JSON数据

var data = {    result: "SUCCESS",    interfaceVersion: "1.0.3",    requested: "10/17/2013 15:31:20",    lastUpdated: "10/16/2013 10:52:39",    tasks: [        {id: 104, complete: false,            priority: "high",                  dueDate: "2013-11-29",      username: "Scott",                  title: "Do something",      created: "9/22/2013"},        {id: 105, complete: false,            priority: "medium",                  dueDate: "2013-11-22",      username: "Lena",                  title: "Do something else", created: "9/22/2013"},        {id: 107, complete: true,             priority: "high",                  dueDate: "2013-11-22",      username: "Mike",                  title: "Fix the foo",       created: "9/22/2013"},        {id: 108, complete: false,            priority: "low",                  dueDate: "2013-11-15",      username: "Punam",                  title: "Adjust the bar",    created: "9/25/2013"},        {id: 110, complete: false,            priority: "medium",                  dueDate: "2013-11-15",      username: "Scott",                  title: "Rename everything", created: "10/2/2013"},        {id: 112, complete: true,             priority: "high",                  dueDate: "2013-11-27",      username: "Lena",                  title: "Alter all quuxes",  created: "10/5/2013"}        // , ...    ]};

需求是找到Scott所有未完成的任务,并按照到期日期升序排列。

正确的结果是

[    {id: 110, title: "Rename everything",         dueDate: "2013-11-15", priority: "medium"},    {id: 104, title: "Do something",         dueDate: "2013-11-29", priority: "high"}]

命令式的代码如下

getIncompleteTaskSummaries = function(membername) {    return fetchData()        .then(function(data) {            return data.tasks;        })        .then(function(tasks) {            var results = [];            for (var i = 0, len = tasks.length; i < len; i++) {                if (tasks[i].username == membername) {                    results.push(tasks[i]);                }            }            return results;        })        .then(function(tasks) {            var results = [];            for (var i = 0, len = tasks.length; i < len; i++) {                if (!tasks[i].complete) {                    results.push(tasks[i]);                }            }            return results;        })        .then(function(tasks) {            var results = [], task;            for (var i = 0, len = tasks.length; i < len; i++) {                task = tasks[i];                results.push({                    id: task.id,                    dueDate: task.dueDate,                    title: task.title,                    priority: task.priority                })            }            return results;        })        .then(function(tasks) {            tasks.sort(function(first, second) {                var a = first.dueDate, b = second.dueDate;                return a < b ? -1 : a > b ? 1 : 0;            });            return tasks;        });};

pointfree的代码

var getIncompleteTaskSummaries = function(membername) {  return fetchData()    .then(R.prop('tasks'))    .then(R.filter(R.propEq('username', membername)))    .then(R.reject(R.propEq('complete', true)))    .then(R.map(R.pick(['id', 'dueDate', 'title', 'priority'])))    .then(R.sortBy(R.prop('dueDate')));};

pointfree的声明式的代码

// 提取 tasks 属性var SelectTasks = R.prop('tasks');// 过滤出指定的用户var filterMember = member => R.filter(  R.propEq('username', member));// 排除已经完成的任务var excludeCompletedTasks = R.reject(R.propEq('complete', true));// 选取指定属性var selectFields = R.map(  R.pick(['id', 'dueDate', 'title', 'priority']));// 按照到期日期排序var sortByDueDate = R.sortBy(R.prop('dueDate'));// 合成函数var getIncompleteTaskSummaries = function(membername) {  return fetchData().then(    R.pipe(      SelectTasks,      filterMember(membername),      excludeCompletedTasks,      selectFields,      sortByDueDate,    )  );};

参考文章

我在github

转载地址:http://mxdja.baihongyu.com/

你可能感兴趣的文章
UNIX域套接字编程和socketpair 函数
查看>>
[LeetCode] Set Intersection Size At Least Two 设置交集大小至少为2
查看>>
Maven update project...后jdk变成1.5,update project后jdk版本改变
查看>>
Android 关于BottomDialogSheet 与Layout擦出爱的火花?
查看>>
【docker】启动docker连接数据库 出现FATAL: password authentucation failed for user "homestatead"问题...
查看>>
python二维数组初始化
查看>>
eclipse 如何修改maven插件本地仓库jar包默认存储位置
查看>>
Zookeeper浏览器工具和Eclipse插件
查看>>
【WPF】UI虚拟化之------自定义VirtualizingWrapPanel
查看>>
银行卡的三个磁道【转】
查看>>
Linux中添加、修改和删除用户和用户组
查看>>
解决eclipse maven 项目重新下载包这个问题
查看>>
appium定位h5
查看>>
获取POM.XML依赖的JAR包
查看>>
文本聚类
查看>>
String 类型的值能够被反射改变从而引发的意外事件
查看>>
eMMC之分区管理、总线协议和工作模式【转】
查看>>
VS.NET IDE <Table>使用小技巧
查看>>
电赛菜鸟营培训(四)——STM32F103CB之ADC转换
查看>>
Win8 Metro中文件读写删除与复制操作
查看>>