什么是函数式编程

函数式编程是声明式编程的一部分。javascript中的函数是第一类公民,这意味着函数是数据,你可以像保存变量一样在应用程序中保存、检索和传递这些函数。

函数式编程有些核心的概念,如下:

  • 不可变性(Immutability)
  • 纯函数(Pure Functions)
  • 数据转换(Data Transformations)
  • 高阶函数 (Higher-Order Functions)
  • 递归
  • 组合

不可变性(Immutability)

不可变性意味着不可改变。 在函数式编程中,你无法更改数据,也不能更改。 如果要改变或更改数据,则必须复制数据副本来更改。

例如,这是一个student对象和changeName函数,如果要更改学生的名称,则需要先复制 student对象,然后返回新对象。

在javascript中,函数参数是对实际数据的引用,你不应该使用 student.firstName =“testing11”,这会改变实际的student 对象,应该使用Object.assign复制对象并返回新对象。

let student = {
    firstName: "testing",
    lastName: "testing",
    marks: 500
}

function changeName(student) {
    // student.firstName = "testing11" //should not do it
    let copiedStudent = Object.assign({}, student);
    copiedStudent.firstName = "testing11";
    return copiedStudent;
}

console.log(changeName(student));

console.log(student);

纯函数

纯函数是始终接受一个或多个参数并计算参数并返回数据或函数的函数。 它没有副作用,例如设置全局状态,更改应用程序状态,它总是将参数视为不可变数据。

我想使用 appendAddress 的函数向student对象添加一个地址。 如果使用非纯函数,它没有参数,直接更改 student对象来更改全局状态。

使用纯函数,它接受参数,基于参数计算,返回一个新对象而不修改参数。

let student = {
    firstName: "testing",
    lastName: "testing",
    marks: 500
}

// 非纯函数
function appendAddress() {
    student.address = {streetNumber:"0000", streetName: "first", city:"somecity"};
}

console.log(appendAddress());

// 纯函数
function appendAddress(student) {
    let copystudent = Object.assign({}, student);
    copystudent.address = {streetNumber:"0000", streetName: "first", city:"somecity"};
    return copystudent;
}

console.log(appendAddress(student));

console.log(student);

数据转换

我们讲了很多关于不可变性的内容,如果数据是不可变的,我们如何改变数据。如上所述,我们总是生成原始数据的转换副本,而不是直接更改原始数据。

再介绍一些 javascript内置函数,当然还有很多其他的函数,这里有一些例子。所有这些函数都不改变现有的数据,而是返回新的数组或对象。

let cities = ["irving", "lowell", "houston"];

// we can get the comma separated list
console.log(cities.join(','))
// irving,lowell,houston

// if we want to get cities start with i
const citiesI = cities.filter(city => city[0] === "i");
console.log(citiesI)
// [ 'irving' ]

// if we want to capitalize all the cities
const citiesC = cities.map(city => city.toUpperCase());
console.log(citiesC)
// [ 'IRVING', 'LOWELL', 'HOUSTON' ]

高阶函数

高阶函数是将函数作为参数或返回函数的函数,或者有时它们都有。 这些高阶函数可以操纵其他函数。

Array.mapArray.filterArray.reduce是高阶函数,因为它们将函数作为参数。

const numbers = [10,20,40,50,60,70,80]

const out1 = numbers.map(num => num * 100);
console.log(out1);
// [ 1000, 2000, 4000, 5000, 6000, 7000, 8000 ]

const out2 = numbers.filter(num => num > 50);
console.log(out2);
// [ 60, 70, 80 ]

const out3 = numbers.reduce((out,num) => out + num);
console.log(out3);
// 330

下面是另一个名为isPersonOld的高阶函数示例,该函数接受另外两个函数,分别是 messageisYoung

const isYoung = age => age < 25;

const message = msg => "He is "+ msg;

function isPersonOld(age, isYoung, message) {
    const returnMessage = isYoung(age)?message("young"):message("old");
    return returnMessage;
}

// passing functions as an arguments
console.log(isPersonOld(13,isYoung,message))
// He is young

递归

递归是一种函数在满足一定条件之前调用自身的技术。只要可能,最好使用递归而不是循环。你必须注意这一点,浏览器不能处理太多递归和抛出错误。

下面是一个演示递归的例子,在这个递归中,打印一个类似于楼梯的名称。我们也可以使用for循环,但只要可能,我们更喜欢递归。

function printMyName(name, count) {
    if(count <= name.length) {
        console.log(name.substring(0,count));
        printMyName(name, ++count);
    }
}

console.log(printMyName("Bhargav", 1));


var name = "Bhargav"
var output = "";
for(let i=0; i<name.length; i++) {
    output = output + name[i];
    console.log(output);
}


组合

在React中,我们将功能划分为小型可重用的纯函数,我们必须将所有这些可重用的函数放在一起,最终使其成为产品。 将所有较小的函数组合成更大的函数,最终,得到一个应用程序,这称为组合。

实现组合有许多不同方法。 我们从Javascript中了解到的一种常见方法是链接。 链接是一种使用点表示法调用前一个函数的返回值的函数的方法。
这是一个例子。 我们有一个name,如果firstNamelastName大于5个单词的大写字母,刚返回,并且打印名称的名称和长度。

const name = "Bhargav Bachina";

const output = name.split(" ")
    .filter(name => name.length > 5)
    .map(val => {
    val = val.toUpperCase();
    console.log("Name:::::"+val);
    console.log("Count::::"+val.length);
    return val;
});

console.log(output)
/*
[ 'BHARGAV', 'BACHINA' ]
*/

在React中,我们使用了不同于链接的方法,因为如果有30个这样的函数,就很难进行链接。这里的目的是将所有更简单的函数组合起来生成一个更高阶的函数。

const name = compose(
    splitmyName,
    countEachName,
    comvertUpperCase,
    returnName
)

console.log(name);
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
 这本书绝不轻易放过每个知识点,全书包含有大量习题,要求你自己实现 Scala 标准库或者 Scalaz 中的既有功能。所以,当你读完本书,做完习题后,虽然你的应用开发能力并不会直接提升,但你会体会到构建函数式语言和框架时的难点和取舍,从而增进你的框架开发和语言设计的能力。   ——ThoughtWorks Lead Consultant 杨博   这本书所讲授的,正是基于 Scala 的函数式编程基础。基于 Scheme、Haskell 等老牌函数式语言的传统教材的问题在于,相关语言的语法和思维方式与读者现有的知识体系迥异,容易造成较为陡峭的入门门槛。此外,由于这些语言本身的实际应用机会不多,初学者也难以在实战中获得宝贵的直觉和经验。而在 Scala 的帮助下,这本书并不要求你抛开现有的思维方式另起炉灶,它所做的更像是为你现有的思维方式添砖加瓦,从而令你如虎添翼。   ——Spark committer from Databricks 连城   尽管函数式编程在近十多年用得越来越多,但市面上介绍其高阶特性的书却并不多。这本书在这方面是个重要的补充,它不仅仅面向 Scala 程序员,同样面向用任何编程语言开发的程序员,只要你充满好奇心。   ——挖财网首席架构师 王宏江   “让你洞察计算的本质。”   ——Martin Odersky, Scala的作者   “Scala和Java8开发者的函数式编程指南!”   ——William E. Wheeler, TekSystems   “本书向你展示了提升Scala技能的方法和理念,它已超过‘更好的Java’。”   ——Fernando Dobladez, Code54   “里面的练习有些挑战,很有趣,对你在真实世界中使用它很有益。”   ——Chris Nauroth, Hortonworks   “边干边学,而非只是阅读。”   ——Douglas Alan、Eli和Edythe L. Broad,哈佛和麻省理工学院

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值