JavaScript中的函数式编程详解

函数式编程

函数式编程是一种编程范式,是一种构建计算机程序结构和元素的风格,它把计算看作是对数学函数的评估,避免了状态的变化和数据的可变,与函数式编程相对的是命令式编程。我们有这样一个需求,给数组的每个数字加一:

// 数组每个数字加一, 命令式编程
let arr = [1, 2, 3, 4];
let newArr = [];
for(let i = 0; i < arr.length; i++){
 newArr.push(arr[i] + 1);
}

console.log(newArr); // [2, 3, 4, 5]

这段代码结果没有问题,但是没法重用。我们换一个思维,这里面包含的操作其实就两个,一个是遍历数组,一个是成员加一。我们把这两个方法拆出来:

// 先拆加一出来
let add1 = x => x +1;

// 然后拆遍历方法出来,通过遍历返回一个操作后的新数组
// fn是我们需要对每个数组想进行的操作
let createArr = (arr, fn) => {
 const newArr = [];
 for(let i = 0; i < arr.length; i++){
 newArr.push(fn(arr[i]));
 }

 return newArr;
} 

// 用这两个方法来得到我们期望的结果
const arr = [1, 2, 3, 4];
const newArr = createArr(arr, add1);
console.log(newArr); // [2, 3, 4, 5], 结果仍然是对的

这样拆分后,如果我们下次的需求是对数组每个元素乘以2,我们只需要写一个乘法的方法,然后复用之前的代码就行:

let multiply2 = x => x * 2;

// 调用之前的createArr
const arr2 = [1, 2, 3, 4];
const newArr2 = createArr(arr2, multiply2);
console.log(newArr2); // [2, 4, 6, 8], 结果是对的

事实上我们的加一函数只能加一,也不好复用,它还可以继续拆:

// 先写一个通用加法,他接收第一个加数,返回一个方法
// 返回的这个方法接收第二个加数,第一个加数是上层方法的a
// 这样当我们需要计算1+2是,就是add(1)(2)
let add = (a) => {
 return (b) => {
 return a + b;
 }
}

// 我们也可以将返回的函数赋给一个变量,这个变量也就变成一个能特定加a的一个方法
let add1 = add(1);

let res = add1(4);
console.log(res); // 5

所以函数式编程就是将程序分解为一些更可重用、更可靠且更易于理解的部分,然后将他们组合起来,形成一个更易推理的程序整体。

纯函数

纯函数是指一个函数,如果它的调用参数相同,则永远返回相同的结果。它不依赖于程序执行期间函数外部任何状态或数据的变化,只依赖于其输入参数。同时函数的运行也不改变任何外部数据,它只通过它的返回值与外部通讯。下面这个函数就不是纯函数,因为函数内部需要的discount需要从外部获取:

let discount = 0.8;
const calPrice = price => price * discount;
let price = calPrice(200); // 160

// 当discount变了,calPrice传同样额参数,结果不一样,所以不纯
discount = 0.9;
price = calPrice(200); // 180

要改为纯函数也很简单,将discount作为参数传递进去就行了

const calPrice = (price, discount) => price * discount;

纯函数可以保证代码的稳定性,因为相同的输入永远会得到相同结果。不纯的函数可能会带来副作用。

函数副作用

函数副作用是指调用函数时除了返回函数值之外,还对主调用函数产生附加的影响,比如修改全局变量或者外部变量,或者修改参数。这可能会带来难以查找的问题并降低代码的可读性。下面的foo就有副作用,当后面有其他地方需要使用a,可能就会拿到一个被污染的值

let a = 5;
let foo = () => a = a * 10;
foo();
console.log(a); // 50

除了我们自己写的函数有副作用外,一些原生API也可能有副作用,我们写代码时应该注意:

我们的目标是尽可能的减少副作用,将函数写为纯函数,下面这个不纯的函数使用了new Date,每次运行结果不一样,是不纯的:

要给为纯函数可以将依赖注入进去,所谓依赖注入就是将不纯的部分提取出来作为参数,这样我们可以让副作用代码集中在外部,远离核心代码,保证核心代码的稳定性

// 依赖注入
const foo = (d, log, something) => {
 const dt = d.toISOString();
 return log(`${dt}: ${something}`);
}

const something = 'log content';
const d = new Date();
const log = console.log.bind(console);
foo(d, log, something);

所以减少副作用一般的方法就是:

1. 函数使用参数进行运算,不要修改参数
2. 函数内部不修改外部变量
3. 运算结果通过返回值返回给外部

可变性和不可变性

  • 可变性:指一个变量创建以后可以任意修改
  • 不可变性: 指一个变量被创建后永远不会发生改变,不可变性是函数式编程的核心概念

下面是一个可变的例子:

如果我们一定要修改这个参数,我们应该将这个参数进行深拷贝后再操作,这样就不会修改参数了:

到此这篇关于JavaScript中的函数式编程详解的文章就介绍到这了,更多相关js函数式编程内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 用函数式编程技术编写优美的 JavaScript_ibm

    因为函数式编程采用了完全不同的组织程序的方式,所以那些习惯于采用命令式范例的程序员可能会发现函数式编程有点难学.在这篇文章中,您将了解一些关于如何采用函数式风格,用 JavaScript 编写良好的.优美的代码的示例.我将讨论: 函数式编程概念,包括匿名函数.调用函数的不同方法,以及将函数作为参数传递给其他函数的方式. 函数式概念的运用,采用的示例包括:扩展数组排序:动态 HTML 生成的优美代码:系列函数的应用. 函数式编程概念 请告诉每个人.请把这个提交给: Digg Slashdot 在那

  • javascript 函数式编程

    JavaScript的函数式编程的对象本质: function a() {     var x="sth";       return b(){         //do with x;      } } var c = a(); 等价于 function a() {         this.x = "dosth";         this.b = function(){               //do with this.x         } } va

  • 《JavaScript函数式编程》读后感

    本文章记录本人在学习 函数式 中理解到的一些东西,加深记忆和并且整理记录下来,方便之后的复习. 在近期看到了<JavaScript函数式编程>这本书预售的时候就定了下来.主要目的是个人目前还是不理解什么是函数式编程.在自己学习的过程中一直听到身边的人说面向过程编程和面向对象编程,而函数式就非常少.为了自己不要落后于其他同学的脚步,故想以写笔记的方式去分享和记录自己阅读中所汲取的知识. js 和函数式编程 书中用了一句简单的话来回答了什么是函数式编程: 函数式编程通过使用函数来将值转换为抽象单元

  • JavaScript 函数式编程的原理

    1,JavaScript中函数.方法的调用 在JavaScript中,有两种调用函数的方式.一般的方式是把参数放在括号中,另一种方式是同时把函数和参数都放在括号中.如: 复制代码 代码如下: function test(x) { alert(x); } test("hello"); (test)("hello"); //等同于下面的代码 (function test(x) { alert(x); })("hello"); //也等同于下面的代码

  • Javascript函数式编程语言

    函数式编程语言 函数式编程语言是那些方便于使用函数式编程范式的语言.简单来说,如果具备函数式编程所需的特征, 它就可以被称为函数式语言.在多数情况下,编程的风格实际上决定了一个程序是否是函数式的. 是什么让一个语言具有函数式特征? 函数式编程无法用C语言来实现.函数式编程也无法用Java来实现(不包括那些通过大量变通手段实现的近似函数式编程). 这些语言不包含支持函数式编程的结构.他们是纯面向对象的.严格非函数式的语言. 同时,纯函数语言也无法使用面向对象编程,比如Scheme.Haskell以

  • 深入探讨javascript函数式编程

    有时,优雅的实现是一个函数.不是方法.不是类.不是框架.只是函数. - John Carmack,游戏<毁灭战士>首席程序员 函数式编程全都是关于如何把一个问题分解为一系列函数的.通常,函数会链在一起,互相嵌套, 来回传递,被视作头等公民.如果你使用过诸如jQuery或Node.js这样的框架,你应该用过一些这样的技术, 只不过你没有意识到. 我们从Javascript的一个小尴尬开始. 假设我们需要一个值的列表,这些值会赋值给普通的对象.这些对象可能包含任何东西:数据.HTML对象等等. v

  • javascript函数式编程实例分析

    本文实例讲述了javascript函数式编程.分享给大家供大家参考.具体分析如下: js像其他动态语言一样是可以写高阶函数的,所谓高阶函数是可以操作函数的函数.因为在js中函数是一个彻彻底底的对象,属于第一类公民,这提供了函数式编程的先决条件. 下面给出一个例子代码,出自一本js教程,功能是计算数组元素的平均值和标准差,先列出非函数式编程的一种写法: var data = [1,1,3,5,5]; var total = 0; for(var i = 0;i < data.length;i++)

  • 用函数式编程技术编写优美的 JavaScript

    级别: 初级 Shantanu Bhattacharya (shantanu@justawordaway.com), 首席顾问, Siemens Information Systems Limited 2006 年 7 月 20 日 函数式或声明性编程是非常强大的编程方法,正逐渐在软件行业流行起来.这篇文章将介绍一些相关的函数式编程概念,并提供有效使用这些概念的示例.作者将解释如何使用 JavaScript(TM)(JavaScript 能导入函数式编程的构造和特性)编写优美的代码. 简介 函数

  • JavaScript与函数式编程解释

    作者:月影 牢记:函数式编程不是用函数来编程!!!23.4函数式编程  23.4.1 什么是函数式编程 什么是函数式编程?如果你这么直白地询问,会发现它竟是一个不太容易解释的概念.许多在程序设计领域有着多年经验的老手,也无法很明白地说清楚函数式编程到底在研究些什么.函数式编程对于熟悉过程式程序设计的程序员来说的确是一个陌生的领域,闭包(closure),延续(continuation),和柯里化(currying)这些概念看起来是这么的陌生,同我们熟悉的if.else.while没有任何的相似之

  • javascript函数式编程程序员的工具集

    如果你仔细看了到目前为止出现过的示例代码,你会发现这里面的一些方法不太熟悉. 它们是map().filter()和reduce()函数,它们对任何语言的函数式编程都至关重要. 它们可以让你不必使用循环和语句,写出更简洁的代码. map().filter()和reduce()函数组成了函数式程序员工具集的核心部分,这个工具集包括一系列纯的. 高阶的函数,它们是函数式方法的主力.实际上,它们是纯函数和高阶函数的典型,它们以一个函数为输入, 返回一个输出结果,并且不产生副作用. 然而它们是浏览器中EC

  • Javascript函数式编程简单介绍

    几十年来,函数式编程一直是计算机科学狂热者的至爱,由于数学的纯洁性和谜一般的本质, 它被埋藏在计算机实验室,只有数据学家和有希望获得博士学位的人士使用.但是现在,它正经历一场复兴, 这要感谢一些现代语言比如Python,Julia,Ruby,Clojure以及--但不是最后一个--Javascript. 你是说Javascript?这个WEB脚本语言?没错! Javascript已经被证明是一项长期以来都没有消失的重要的技术.这主要是由于它扩展的一些框架和库而使其具有重生的能力, 比如backb

  • JavaScript 函数式编程实践(来自IBM)第1/3页

    函数式编程简介 说到函数式编程,人们的第一印象往往是其学院派,晦涩难懂,大概只有那些蓬头散发,不修边幅,甚至有些神经质的大学教授们才会用的编程方式.这可能在历史上的某个阶段的确如此,但是近来函数式编程已经在实际应用中发挥着巨大作用了,而更有越来越多的语言不断的加入诸如 闭包,匿名函数等的支持,从某种程度上来讲,函数式编程正在逐步"同化"命令式编程. 函数式编程思想的源头可以追溯到 20 世纪 30 年代,数学家阿隆左 . 丘奇在进行一项关于问题的可计算性的研究,也就是后来的 lambd

  • js 函数式编程学习笔记

    (1)平常写的函数大多是接受值,合并值,返回值,比如经常写的for循环: function printArray(array){ for(var i=0;i<array.length;i++){ print(array[i]); } } 但是如果我们想做print之外的事情呢?怎么办?再写一个相似的,未免显得浪费,我们可以这样 function forEach(array,action){ for(var i=0;i<array.length;i++){ action(array[i]); }

  • 比较不错的函数式JavaScript编程指南教程

    你是否知道JavaScript其实也是一个函数式编程语言呢?本指南将教你如何利用JavaScript的函数式特性. 要求:你应当已经对JavaScript和DOM有了一个基本的了解. 写这篇指南的目的是因为关于JavaScript编程的资料太多了但是极少的资料提到了JavaScript的函数式特性.在本指南中,我只会讲解这些基本知识而不会深入其它的函数式语言或这是Lambda算子. 你可以点击所有的例子然后你所看到的代码就会被执行,这样就可以令指南变得具有交互性.你也可以使用这个沙箱来尝试. 第

  • 使用 JavaScript 进行函数式编程 (一) 翻译

    编程范式 编程范式是一个由思考问题以及实现问题愿景的工具组成的框架.很多现代语言都是聚范式(或者说多重范式): 他们支持很多不同的编程范式,比如面向对象,元程序设计,泛函,面向过程,等等. 函数式编程范式 函数式编程就像一辆氢燃料驱动的汽车--先进的未来派,但是还没有被广泛推广.与命令式编程相反,他由一系列语句组成,这些语句用于更新执行时的全局状态.函数式编程将计算转化作表达式求值.这些表达式全由纯数学函数组成,这些数学函数都是一流的(可以被当做一般值来运用和处理),并且没有副作用. 函数式编程

  • JavaScript的函数式编程基础指南

    引言 JavaScript是一种强大的,却被误解的编程语言.一些人喜欢说它是一个面向对象的编程语言,或者它是一个函数式编程语言.另外一些人喜欢说,它不是一个面向对象的编程语言,或者它不是一个函数式编程语言.还有人认为它兼具面向对象语言和函数式语言的特点,或者,认为它既不是面向对象的也不是函数式的,好吧,让我们先搁置那些争论. 让我们假设我们共有这样的一个使命:在JavaScript语言所允许的范围内,尽可能多的使用函数式编程的原则来编写程序. 首先,我们需要清理下脑子里那些关于函数式编程的错误观

  • 浅谈javascript函数式编程

    函数式编程,属于编程范式的一种 1 函数是第一公民,可以返回值,也可以作为其他函数的参数 //console是一个函数 function con(v){ console.log(v) } // execute 也是一个函数 function execute(fn){ fn(1) } //将con函数作为参数传进execute函数 execute(con) // 1 2 接近自然语言的写法 晓池吃完饭然后就去洗澡 可以表现为eat().bathe() // 吃饭函数 function eat(ea

  • 详解用函数式编程对JavaScript进行断舍离

    我和JavaScript 从1997年网景的Navigator 3浏览器开始就开始使用JavaScript.当时,JavaScript还只能做一些很简单的事情.我记得最酷的就是用JavaScript实现mouseover特性,在那个时候已经算得上是高科技了!当鼠标移过去之后,文本内容就神奇的改变了.因为当时都是pre-DHTML,你根本不需要隐藏或则显示DOM元素. 关于DHTML DHTML是Dynamic HTML的简称,就是动态的html(标准通用标记语言下的一个应用),是相对传统的静态的

  • 函数式JavaScript编程指南

    简介 你是否知道JavaScript其实也是一个函数式编程语言呢?本指南将教你如何利用JavaScript的函数式特性. 要求:你应当已经对JavaScript和DOM有了一个基本的了解. 写这篇指南的目的是因为关于JavaScript编程的资料太多了但是极少的资料提到了JavaScript的函数式特性.在本指南中,我只会讲解这些基本知识而不会深入其它的函数式语言或这是Lambda算子. 你可以点击所有的例子然后你所看到的代码就会被执行,这样就可以令指南变得具有交互性.你也可以使用这个沙箱来尝试

随机推荐