探究JavaScript函数式编程的乐趣


Posted in Javascript onDecember 14, 2015

编程范式

编程范式是一个由思考问题以及实现问题愿景的工具组成的框架。很多现代语言都是聚范式(或者说多重范式): 他们支持很多不同的编程范式,比如面向对象,元程序设计,泛函,面向过程,等等。

探究JavaScript函数式编程的乐趣

函数式编程范式

函数式编程就像一辆氢燃料驱动的汽车——先进的未来派,但是还没有被广泛推广。与命令式编程相反,他由一系列语句组成,这些语句用于更新执行时的全局状态。函数式编程将计算转化作表达式求值。这些表达式全由纯数学函数组成,这些数学函数都是一流的(可以被当做一般值来运用和处理),并且没有副作用。

探究JavaScript函数式编程的乐趣

函数式编程很重视以下值:
函数是一等要务

我们应该将函数与编程语言中的其他类对象同样对待。换句话说,您可以将函数存储在变量里,动态创建函数,以及将函数返回或者将函数传递给其他函数。下面我们来看一个例子...

 探究JavaScript函数式编程的乐趣

一个字符串可以保存为一个变量,函数也可以,例如:

var sayHello = function() { return “Hello” };

一个字符串可以保存为对象字段,函数也可以,例如:
var person = {message: “Hello”, sayHello: function() { return “Hello” }};

一个字符串可以再用到时才创建,函数也可以,例如:
“Hello ” + (function() { return “World” })(); //=> Hello World

一个字符串可以作为输入参数传给函数,则函数也可以:
function hellloWorld(hello, world) { return hello + world() }

一个字符串可以作为函数返回值,函数也可以,例如:
return “Hello”;
return function() { return “Hello”};

高阶案例

探究JavaScript函数式编程的乐趣

如果函数将其他函数函数作为输入参数或者作为返回值,则称之为高阶函数。刚才我们已经看过了一个高阶函数的例子。下面,我们来看一下更复杂的情况。
例1:

[1, 2, 3].forEach(alert);
// alert 弹窗显示“1" 
// alert 弹窗显示 "2" 
// alert 弹窗显示 "3”

例2:

function splat(fun) {
  return function(array) {
    return fun.apply(null, array);
  };
}
var addArrayElements = splat(function(x, y) { return x + y });
addArrayElements([1, 2]);
//=> 3

最爱纯函数

探究JavaScript函数式编程的乐趣

纯函数不会有其他的副作用,所谓的副作用指的是函数所产生的对函数外界状态的修改。比如:

  • 修改某个变量
  • 修改数据结构
  • 对外界某个变量设置字段
  • 抛出例外或者弹出错误信息

最简单的例子就是数学函数。Math.sqrt(4) 函数总是返回2。他不会用到任何其他心寒信息,如状态或者设置参数。数学函数从来不会造成任何副作用。

避免修改状态


探究JavaScript函数式编程的乐趣

函数式编程支持纯粹的函数,这样的函数不能改变数据,因此大多用于创建不可改变的的数据。这种方式,不用修改一个已存在的数据结构,而且能高效的新建一个.
你也许想知道,如果一个纯粹的函数通过改变一些本地数据而生产一个不可改变的返回值,是否是允许的?答案是可以。
在JavaScript中极少的数据类型是默认是不可改变的。String是一个不能被改变的数据类型的例子:

var s = "HelloWorld";
  s.toUpperCase();
  //=> "HELLOWORLD"
  s;
  //=> "HelloWorld"

不可改变状态的好处

    •    避免混乱和增加程序的准确性:在复杂系统内,大多数难以理解的Bug是由于状态通过在程序中外部客户端代码修改而导致的。

    •    确立“快速简洁”的多线程编程:如果多线程可以修改同一个共享值,你不得不同步的获取值。这对专家来说都是十分乏味并且易出错的编程挑战。

软件事务内存和Actor模型提供了直接在线程安全方式下处理修改。

使用递归而非循环调用

探究JavaScript函数式编程的乐趣

递归是最有名的函数式编程技术。如果您还不知道它的话,那么可以理解为递归函数就是一个可以调用自己的函数。
替代反复循环的最经典方式就是使用递归,即每次完成函数体操作之后,再继续执行集合里的下一项,直到满足结束条件。递归还天生符合某些算法实现,比如遍历树形结构(每个树枝都是一颗小树)。
在任何语言里,递归都是一项重要的函数式编程方式。很多函数语言甚至要求的更加严格:只支持递归遍历,而不支持显式的循环遍历。这需要语言必须保证消除了尾端调用,这是 JavasSrip 不支持的。

惰性求值优于激进计算

探究JavaScript函数式编程的乐趣

数学定义了很多无穷集合,比如自然数(所有的正整数)。他们都是符号表示。任意特定有限的子集都在需要时求值。我们将其称之为惰性求值(也叫做非严格求值,或者按需调用,延迟执行)。及早求值会强迫我们表示出所有无穷数据,而这显然是不可能的。
很多语言都默认是惰性的,有些也提供了惰性数据结构以表达无穷集合,并在需要时对自己进行精确计算。
很明显一行代码 result = compute() 所表达的是将 compute() 的返回结果赋值给 result。但是 result 的值究竟是多少只有其被用到的时候才有意义。
可见策略的选择会在很大程度上提高性能,特别是当用在链式处理或者数组处理的时候。这些都是函数式程序员所喜爱的编程技术。
这就开创可很多可能性,包括并发执行,并行技术以及合成。
但是,有一个问题,JavaScrip 并不对自身进行惰性求值。话虽如此,Javascript 里的函数库可以有效地模拟惰性求值。
闭包的全部好处

所有的函数式语言都有闭包,然而这个语言特性经常被讨论得很神秘。闭包是一个函数,这个函数有着对内部引用的所有变量的隐式绑定。换句话说,该函数对它引用的变量封闭了一个上下文。JavaScript 中的闭包是能够访问父级作用域的函数,即使父级函数已经调用完毕。

function multiplier(factor) {
   return function(number) {
     return number * factor;
   };
  }
 var twiceOf = multiplier(2);
  console.log(twiceOf(6));
//=> 12

声明式优于命令式编程

函数式编程是声明式的,就像数学运算,属性和关系是定义好的。运行时知道怎么计算最终结果。阶乘函数的定义提供了一个例子:
factorial(n)       = 1 if n = 1
                            n * factorial(n-1) if n > 1
该定义将 factorial(n) 的值关联到 factorial(n-1),是递归定义。特殊情况下的 factorial(1) 终止了递归。

var imperativeFactorial = function(n) {
  if(n == 1) {
    return 1
  } else {
    product = 1;
    for(i = 1; i <= n; i++) {
       product *= i;
    }
    return product;
   }
}
var declarativeFactorial = function(n) {
    if(n == 1) {
       return 1
    } else {
       return n * factorial(n - 1);
   }
 }

从它实现阶乘计算来看,声明式的阶乘可能看起来像“命令式”的,但它的结构更像声明式的。
命令式阶乘使用可变值、循环计数器和结果来累加计算后的结果。这个方法显式地实现了特定的算法。不像声明式版本,这种方法有许多可变步骤,导致它更难理解,也更难避免 bug 。

探究JavaScript函数式编程的乐趣

函数式JavaScript库

有很多函数式库:underscore.js, lodash,Fantasy Land, Functional.js, Bilby.js, fn.js, Wu.js, Lazy.js, Bacon.js, sloth.js, stream.js, Sugar, Folktale, RxJs 等等。
函数式程序员工具包

map(), filter(), 和 reduce()函数 构成了函数式程序员工具包的核心。 纯高阶函数成了函数式方法的主力。事实上,它们是纯函数和高阶函数应该仿效的典型。它们用一个函数作为输入,返回没有副作用的输出。
这些 JavaScript 函数对每一个函数式程序来说都是至关重要的。他们可以去除循环和语句,使得代码更加整洁。这些都是实现 ECMAScript5.1 的浏览器的标准,他们只处理数组。每次调用都会创建创建并返回一个新的数组。已存在的数组不会被修改。但是稍等,事情很不止于此。。。他们还将函数作为输入参数,通常是作为回调的匿名函数。他们会遍历将整个数组并且将该回调函数应用与每一项!
myArray = [1,2,3,4];
newArray = myArray.map(function(x) {return x*2});
console.log(myArray); // Output: [1,2,3,4]
console.log(newArray); // Output: [2,4,6,8]
除了这三个函数,还有很多函数可以扎入到几乎每一个函数式应用里:
forEach(),concat(), reverse(), sort(), every() 以及some().
JavaScript的聚范式

JavaScript当然不是严格意义上的函数式编程语言,这也促使了对其他范式的使用:
命令式编程:基于详细操作描述式的编程
基于原型的面向对象式编程:基于原型对象及其实例的编程
元程序编程:操纵JavsScript执行模型的编程方式。对元程序编程的一个很好的定义描述为“编程发生在您书写代码做某事的时候,而元程序编程则发生在您书写代码导致某事的解释方式发生变化的时候。

以上就是JavaScript函数式编程的使用方法,希望对大家的学习有所帮助。

Javascript 相关文章推荐
javascript 判断数组是否已包含了某个元素的函数
May 30 Javascript
document.addEventListener使用介绍
Mar 07 Javascript
jQuery验证插件 Validate详解
Nov 20 Javascript
php+ajax+jquery实现点击加载更多内容
May 03 Javascript
javascript实现图片延迟加载方法汇总(三种方法)
Aug 27 Javascript
jQuery限制图片大小的方法
May 25 Javascript
BootStrap学习系列之布局组件(下拉,按钮组[toolbar],上拉)
Jan 03 Javascript
jQuery Form表单取值的方法
Jan 11 Javascript
如何理解Vue的.sync修饰符的使用
Aug 17 Javascript
微信小程序自定义可滑动顶部TabBar选项卡实现页面切换功能示例
May 14 Javascript
vue 组件内获取actions的response方式
Nov 08 Javascript
Vue中函数防抖节流的理解及应用实现
Apr 24 Javascript
jQuery+json实现的简易Ajax调用实例
Dec 14 #Javascript
以JavaScript来实现WordPress中的二级导航菜单的方法
Dec 14 #Javascript
JS实现DIV容器赋值的方法
Dec 14 #Javascript
JavaScript中eval()函数用法详解
Dec 14 #Javascript
JS实现单击输入框弹出选择框效果完整实例
Dec 14 #Javascript
JavaScript实现点击按钮就复制当前网址
Dec 14 #Javascript
JavaScript 实现的 zip 压缩和解压缩工具包Zip.js使用详解
Dec 14 #Javascript
You might like
Apache设置虚拟WEB
2006/10/09 PHP
解决GD中文乱码问题
2007/02/14 PHP
php数组函数序列之array_pop() - 删除数组中的最后一个元素
2011/11/07 PHP
php常用文件操作函数汇总
2014/11/22 PHP
php+jQuery.uploadify实现文件上传教程
2014/12/26 PHP
PHP实现批量修改文件后缀名的方法
2015/07/30 PHP
PHP易混淆知识整理笔记
2015/09/24 PHP
php Session无效分析资料整理
2016/11/29 PHP
php文件管理基本功能简单操作
2017/01/16 PHP
laravel excel 上传文件保存到本地服务器功能
2019/11/14 PHP
Ext面向对象开发实践(续)
2008/11/18 Javascript
CSS图片响应式 垂直水平居中
2015/08/14 Javascript
URL的参数中有加号传值变为空格的问题(URL特殊字符)
2016/11/04 Javascript
Vue方法与事件处理器详解
2016/12/01 Javascript
详解如何在Vue2中实现组件props双向绑定
2017/03/29 Javascript
基于vue.js路由参数的实例讲解——简单易懂
2017/09/07 Javascript
100行代码实现vue表单校验功能(小白自编)
2019/11/19 Javascript
vue element table中自定义一些input的验证操作
2020/07/18 Javascript
python数据清洗系列之字符串处理详解
2017/02/12 Python
python 接口返回的json字符串实例
2018/03/27 Python
对Python3中的print函数以及与python2的对比分析
2018/05/02 Python
Linux系统(CentOS)下python2.7.10安装
2018/09/26 Python
利用arcgis的python读取要素的X,Y方法
2018/12/22 Python
与Django结合利用模型对上传图片预测的实例详解
2019/08/07 Python
解决django xadmin主题不显示和只显示bootstrap2的问题
2020/03/30 Python
实现Python3数组旋转的3种算法实例
2020/09/16 Python
python 下载文件的多种方法汇总
2020/11/17 Python
如何开发一款堪比APP的微信小程序(腾讯内部团队分享)
2016/12/22 HTML / CSS
美国二手奢侈品寄售网站:TheRealReal
2016/10/29 全球购物
法国春天百货官网:Printemps.com
2020/06/29 全球购物
一年级语文教学反思
2014/02/13 职场文书
环保守法证明
2015/06/24 职场文书
工作态度怎么写
2015/06/25 职场文书
2019七夕节祝福语36句,快来收藏吧
2019/08/06 职场文书
Mysql 如何批量插入数据
2021/04/06 MySQL
python 判断文件或文件夹是否存在
2022/03/18 Python