博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
如何使用函数式编程?
阅读量:6902 次
发布时间:2019-06-27

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

由于最近面试的原因,一直没有更新博文,最近有时间了,谈一下一直在研究的函数式编程的使用。

函数式编程,从接触以来似乎没怎么使用,据说backbone的依赖是underscore,是不是也是函数式呢?redux不依赖underscore,是不是函数式呢?

backbone这个不清楚,反正在redux中或多或少的使用了函数式编程的理念,用到函数式编程(以下简称为fp)的compose函数来处理它的reducer。

那么fp到底该怎么用,它有什么好处呢?                  系统的学习fp可到这里来--> 当然,买本《functional javascript》也是不错的~

您也可以看一下我的这篇博文--《》里面讲了本例子所用到的主要函数~

-----------------------正文分割线-------------------------------------------

引用一句话说:我们要开始转变观念了,从现在开始,我们将不再指示计算机如何工作,而是指出我们明确希望得到的结果。

先举个栗子~

 这是命令式编程

var makes = [];for (i = 0; i < cars.length; i++) {  makes.push(cars[i].make);}

这是声明式编程

var makes = cars.map(function(car){ return car.make; });

我觉得高低立分,声明式的map函数是一个表达式,直观而且自由度很大。我们可以随意更改makes的内容,而这些都是命令式达不到的。fp的优势就是这样。

从书上找一个例子来说明fp是怎样编程的:

这个例子是获取图片,然后展示在浏览器上。

这是html结构:

              

flickr.js的内容:

requirejs.config({  paths: {    ramda: 'https://cdnjs.cloudflare.com/ajax/libs/ramda/0.13.0/ramda.min',    jquery: 'https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min'  }});require([    'ramda',    'jquery'  ],  function (_, $) {    var trace = _.curry(function(tag, x) {      console.log(tag, x);      return x;    });    // app goes here  });

是一个fp的库,就类似于underscore和lodash,本例子用了requirejs,虽然我不怎么喜欢这个框架,为保持一致性,就一直用require了。

这个flickr.js就是用require加载了ramda和jquery,声明了trace函数用来在fp的流中打印当前流的值,其实排错用,暂时忽略它。

本应用的任务呢?

  1. 根据特定搜索关键字构造 url
  2. 向 flickr 发送 api 请求
  3. 把返回的 json 转为 html 图片
  4. 把图片放到屏幕上

上面提到了2个不纯的动作:从api获取数据和把图片放到屏幕上,我们先把不纯的动作写出来,以便分离开其他纯的动作。

var Impure = {  getJSON: _.curry(function(callback, url) {    $.getJSON(url, callback);  }),  setHtml: _.curry(function(sel, html) {    $(sel).html(html);  })};

在 Impure 命名空间下,这样我们就知道它们都是危险函数。

简单了封装了jquery的getJSON和jquery的html。就可以用Impure.getJSON(url,callback)来调用啦。

var url = function (term) {  return 'https://api.flickr.com/services/feeds/photos_public.gne?tags=' + term + '&format=json&jsoncallback=?';};

封装获得url的函数。

好,我们把方法都写完了,现在开始fp之旅。

利用compose组合了获取url和获取图片这个任务。app("cats");就可以得到cats图片的src,回掉函数是trace("response"),它会打印服务器的返回。

var app = _.compose(Impure.getJSON(trace("response")), url);app("cats");

如果命令式编程的话会写为

var _url = url("cat");Impure.getJSON(_url,trace("response"));

这样就不是那么简洁自由了。

这会调用 url 函数,然后把字符串传给 getJSON 函数。getJSON 已经局部应用了 trace,加载这个应用将会把请求的响应显示在 console 里。

得到这个json后,我们想要从这个 json 里构造图片,但是 src 都在 items 数组中的每个 media 对象的 m 属性上

然后实现一个辅助函数:

var prop = _.curry(function(property, object){  return object[property];});

这个其实就是_.prop了。很无聊是不是。。

然后呢,获取图片url,

var mediaUrl = _.compose(_.prop('m'), _.prop('media'));var srcs = _.compose(_.map(mediaUrl), _.prop('items'));

从json里面取到items属性,然后取media属性,然后取m属性。。一系列的取值运算都用compose来执行。

然后把它整合到html里:

var renderImages = _.compose(Impure.setHtml("body"), srcs);var app = _.compose(Impure.getJSON(renderImages), url);

app方法是把字符串通过url形成需要捕获的url字符串,然后放到getJSON里获取,然后返回renderImage方法。

renderImage函数是把得到的src传到body里,body里会显示图片的src。

这个方法是真正把图片添加到html里。

var img = function (url) {  return $('', { src: url });};

这是真正render图片的renderImages方法。与上面的renderImages方法不一样的地方就是在setHtml的时候不是把srcs放到body了,它加了img标签了。

images就是把srcs组装成html里的img标签。

var images = _.compose(_.map(img), srcs);var renderImages = _.compose(Impure.setHtml("body"), images);var app = _.compose(Impure.getJSON(renderImages), url);

这样就完成了~

最后执行

app("cats");

的时候,这一系列工具链启动了,cats传入url里面封装成需要捕获的url,然后传到getJSON里面获取。getJSON的callback又是renderImages,renderImages把得到的src组装到img标签,然后扔到body里。然后这些工作就完成了。

只说做什么,不说怎么做。这就是fp。我们只传入了cats,这是我们需要的cat图片,然后怎么做呢,这些函数通过compose完成自己的功能。然后通过compose组合起来,完成这个项目的应用。

是不是觉得清晰了很多,而且每一步都是可变的,就像gulp执行pipe,增加一个流的处理是很简单的,对管道的流的处理可以改变整个结果。

 

完整代码:

requirejs.config({  paths: {    ramda: 'https://cdnjs.cloudflare.com/ajax/libs/ramda/0.13.0/ramda.min',    jquery: 'https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min'  }});require([    'ramda',    'jquery'  ],  function (_, $) {    ////    // Utils    var Impure = {      getJSON: _.curry(function(callback, url) {        $.getJSON(url, callback);      }),      setHtml: _.curry(function(sel, html) {        $(sel).html(html);      })    };    var img = function (url) {      return $('', { src: url });    };    var trace = _.curry(function(tag, x) {      console.log(tag, x);      return x;    });    ////    var url = function (t) {      return 'https://api.flickr.com/services/feeds/photos_public.gne?tags=' + t + '&format=json&jsoncallback=?';    };    var mediaUrl = _.compose(_.prop('m'), _.prop('media'));    var srcs = _.compose(_.map(mediaUrl), _.prop('items'));    var images = _.compose(_.map(img), srcs);    var renderImages = _.compose(Impure.setHtml("body"), images);    var app = _.compose(Impure.getJSON(renderImages), url);    app("cats");  });

 

转载于:https://www.cnblogs.com/dh-dh/p/5405571.html

你可能感兴趣的文章
后端传给前端Long类型数据,导致精度丢失
查看>>
SpringMvc 与 Struts2的区别
查看>>
实验四 恶意代码技术
查看>>
快速打出System.out.println("");
查看>>
kermit的安装、配置、使用
查看>>
shell编程学习
查看>>
忙中记录
查看>>
Js点餐加减数量
查看>>
【转】ACM训练计划
查看>>
Design Tic-Tac-Toe
查看>>
LeetCode 477: Total Hamming Distance
查看>>
win10安装MarkdownPad 2报错This view has crashed的处理及md简单语法
查看>>
Unity3D - 设计模式 - 工厂模式
查看>>
第二十六课:jQuery对事件对象的修复
查看>>
Leetcode题目:Swap Nodes in Pairs
查看>>
Windows聚焦转为图片
查看>>
POJ NOI0101-09 字符菱形
查看>>
jQuery--停止动画和判断是否处于动画状态stop()
查看>>
1-1 接口自动化测试框架从设计到开发
查看>>
MYSQL常用命令
查看>>