摘要:源起函数式编程近几年非常流行经常可以在网上看到别人讨论相关话题我机缘巧合之下在上看到有人提到一个讲函数式编程的视频看过之后突然茅塞顿开瞬间把之前零碎的关于函数式编程的知识一下子都联系了起来于是自己希望趁有空把这些知识总结一下这样既可以回顾下
源起
函数式编程近几年非常流行,经常可以在网上看到别人讨论相关话题. 我机缘巧合之下在github上看到有人提到一个讲js函数式编程的视频,看过之后突然茅塞顿开,瞬间把之前零碎的关于函数式编程的知识一下子都联系了起来, 于是自己希望趁有空把这些知识总结一下, 这样既可以回顾下知识耶没准能帮到一些对函数式编程感兴趣的朋友们.
为什么需要函数式编程其实千万别被这看似高深的名字吓怕了, 其实我们码农用这种编程思想无非是为了能更爽的写好代码. 总结一下函数式编程的优点有以下两个优点:
Less bug: 可读性高, 逻辑上更容易理解.
less Time: 更高的抽象层级, 代码高度可复用.
高阶函数(Higher-order functions)这里又一个炫酷屌的名字: "高阶函数". 别怕, 本文并不涉及高等数学的知识就可以让你了解高阶函数的概念. 但是等等! 高阶函数跟函数式编程又有毛关系? 其实简单的说就是高阶函数的特性让我们可以实现函数式编程.
废话不多说, 下面就简单说下什么是高阶函数:
Functions that operate on other functions, either by taking them as arguments or by returning them, are called higher-order functions.
从定义可以知道高阶函数就是可以把函数作为变量传入别的函数, 或者一个函数的返回值是一个函数的函数. 如果上面的话把你绕晕了那么我来简单的概括下就是函数可以被当作变量在程序中传来传去. 下面举几个例子:
//把函数当成变量 var foo = (x) => console.log(x) //把函数当作参数传入另一个函数 var bar = (y, fn) => fn(y) foo("FP is good") // FP is good bar("FP is great", foo) //FP is great
下面这个例子更能体现高阶函数的便利性, 如果我们要遍历数组并且打印数组元素的信息, 你会怎么做?
var arr = [1,1,2,3,5,8] function traverseArray(arr) { for (let i = 0; i < arr.length; i++) { console.log(`index: ${i}, value: ${arr[i]}`) } } traverseArray(arr)
Easy enough! 如果用函数式编程的思维重写上面的代码应该是这个样子的:
function forEach(arr, fn) { for (let i = 0; i < arr.length; i++) { fn(i, arr[i], arr) } } forEach(arr, (index, value) => console.log(`index: ${index}, value: ${value}`))
WTF!? 说好的函数式编程更简洁代码量更少呢! 明显第二种写法写的代码更多啊. 别急, 其实es5的时候JS已经把一系列高阶函数设置好了,比如forRach, map, reduce, filter, every.. 让我们用js的array.forEach重写上面的代码:
arr.forEach((v, k) => console.log(`index: ${k}, value: ${v}`))
怎么样, 一样代码解决战斗。 也许看到这里你还是觉得没什么意思,毕竟虽然代码量少了些,但也没感觉有什么本质性的变化. 下面我会举几个比较常见的例子,通过例子让我们一起体会这种有趣的编程思想,也许看过之后你的想法会有所改变.
常用方法举例先介绍下几个常用的函数, filter, map, reduce:
var animals = [ {name: "a" , species: "dog", weight: 11}, {name: "b", species: "cat", weight: 10}, {name: "c", species: "fish", weight: 1}, {name: "d", species: "cat", weight: 8}, {name: "e", species: "rabbit", weight: 3} ] // 找到所有种类为猫的动物 animals.filter((animal) => animal.species === "cat") // [ { name: "b", species: "cat" }, { name: "d", species: "cat" } ] // 返回所有动物的名字 animals.map((animal) => animal.name) // [ "a", "b", "c", "d", "e" ] // 动物总重 animals.reduce((pre, animal) => pre + animal.weight, 0) //33
怎么样? 如果用循环来写肯定不可能一行代码就搞定吧. 让我们看一些更深入更有意思的例子吧.
比如这道比较经典的算法题: 给定一个字符串"abcdaabc"统计每个字符的出现次数.
// 一般做法是这样的 var str="abcdaabc" var count = {}; var i; for(i=0;i(pre[cur]++ || (pre[cur] = 1), pre), {})
由上面的例子可见, 高阶函数的特性让我们在处理这类问题时比普通的方法要方便的多. 在更实际的应用场景中函数式编程的便利性更能充分的体现, 其中一个经典的例子是统计文本中出现频率最高的十个单词:
var fs = require("fs"); var content = fs.readFileSync("words.txt").toString(); var words = content.split(/[s.,/: ]+/); // 把单词全部变为小写并利用上一个例子的方法统计单词出现的次数 var tally = words.map((word) => word.toLowerCase()) .reduce((pre, cur) => (pre[cur]++ || (pre[cur]=1), pre), {}) //把object的key变成数组并进行排序 var top10 = Object.keys(tally) .map((key) => { return {word: key, count: tally[key]} }) .sort((a, b) => b.count - a.count) .slice(0, 10) console.log(top10)
上面这个例子充分体现了函数式编程思想的魅力,代码精简并且可读性高! 想一想如果你要用循环来写有多多少行代码!
好了, 总结完毕, 最后附上参考资料.
Functional programming in JavaScript
Functional Programming By Example
Eloquent javascript - chapter6
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/86389.html
摘要:前言最近花了不少时间接触学习的函数式的编程方式,而后为了加深理解,又去折腾。不过幸运的是,天生具备了函数式编程的基本元素,所以学习的起点不会太低。初接触第一个实例,函数式编程是如何做一个番茄炒鸡蛋的。 前言 最近花了不少时间接触学习javascript的函数式的编程方式,而后为了加深理解,又去折腾haskell。 不同于人们比较熟悉的命令式编程,如面向对象编程(oop),函数式编程(f...
摘要:参考链接面向对象编程模型现在的很多编程语言基本都具有面向对象的思想,比如等等,而面向对象的主要思想对象,类,继承,封装,多态比较容易理解,这里就不多多描述了。 前言 在我们的日常日发和学习生活中会常常遇到一些名词,比如 命令式编程模型,声明式编程模型,xxx语言是面向对象的等等,这个编程模型到处可见,但是始终搞不清是什么?什么语言又是什么编程模型,当你新接触一门语言的时候,有些问题是需...
摘要:为此决定自研一个富文本编辑器。例如当要转化的对象有环存在时子节点属性赋值了父节点的引用,为了关于函数式编程的思考作者李英杰,美团金融前端团队成员。只有正确使用作用域,才能使用优秀的设计模式,帮助你规避副作用。 JavaScript 专题之惰性函数 JavaScript 专题系列第十五篇,讲解惰性函数 需求 我们现在需要写一个 foo 函数,这个函数返回首次调用时的 Date 对象,注意...
阅读 3816·2021-10-09 09:43
阅读 2843·2021-10-08 10:05
阅读 2717·2021-09-08 10:44
阅读 854·2019-08-30 15:52
阅读 2778·2019-08-26 17:01
阅读 2980·2019-08-26 13:54
阅读 1632·2019-08-26 10:48
阅读 789·2019-08-23 14:41