JavaScript中的函数式编程--函数
2020/7/2 11:55:36
本文主要是介绍JavaScript中的函数式编程--函数,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
为什么学习函数式编程
- 函数式编程是随着React的流行收到越来越多的关注,React中的高阶组件使用高阶函数老实现,高阶函数就是函数式编程的一个特性;再就是React中的redux也是使用了函数式编程的思想
- iOS中的自动布局框架Masonry也是使用函数式编程实现的
- 在新发布的vue3中也是用了大量了高阶函数,由此可见在流行的框架中(React、vue、Masonry)都趋向于函数式编程,也可以说你可以补血新框架,但是不能不学函数式编程
- 使用函数式编程时可以最大限度的抛弃烦人的this
- 使用函数式编程在打包过程中可以更好的利用tree shaking过滤掉无用代码
- 使用函数式编程还能方便测试、并行处理等操作
- 很多流行库能帮助我们使用函数式编程,如:lodash、underscore、ramda等
什么是函数式编程
函数式编程(Functional Programming,FP),FP是编程的一种范式,我们常见的编程范式还有面向对象、面向过程。
- 面向对象编程:就是把现实世界中的事物抽象成编程世界中的类和对象,通过封装、集成和多态来演示事物事件中间的联系
- 函数式编程:就是把现实世界中的事物和事物之间的联系抽象到程序世界(对运算过程进行抽象)
- 程序的本质:根据输入通过某种运算获得相应的输出,程序开发过程中会涉及到很多输入输出函数
- 使用数学中的映射表示:x -> f(联系/映射) -> y,即:y=f(x);再比如:y=sin(x)
- 特点:相同的输入始终得到相同的输出(即纯函数)
- 一句话描述函数式编程:用来描述数据(函数)之间的映射,是对运算过程的抽象
代码示例:计算两个数的和
// 非函数式(按步骤,面向过程) let num1 = 1 let num2 = 2 let sum = num1 + num2 // 函数式(把过程抽象成函数) function add(n1, n2) { return n1 + n2 } let sum = add(1, 2) 复制代码
函数是一等公民
一等公民,MDN解释:First-class Function 在JavaScript中函数就是一个普通的对象,既然是对象,那我们就可以把函数存储到变量/数组/对象中,它还可以作为其他函数的参数和返回值使用,也可以再程序运行过程中通过 new Function('alert("xx")')来构造一个新的函数
函数可以存储在变量中
直接代码演示
// 函数赋值给变量 let fn = function() { console.log('first-class Function') } fn() // 函数存储示例 const BlogController = { index(posts) { return Views.index(posts) }, show(posts) { return Views.show(posts) }, create(attrs) { return Db.create(attrs) }, update(posts, attrs) { return Db.update(posts, attrs) }, destory(posts) { return Db.destory(posts) } } // 示例优化(通过将一个函数/方法赋值给另一个变量) const BlogController = { index: Views.index, show: Views.show, create: Db.create, update: Db.update, destory: Db.destory } 复制代码
函数作为参数使用
高阶函数
高阶函数: Highter-order function
- 可以把函数作为参数传递给另一个函数
- 可以把函数作为另一个函数的返回结果
示例:高阶函数-函数作为参数
// 模拟forEach function forEach(array, fn) { if (Object.prototype.toString.call(array) !== '[object Array]' || typeof fn !== "function") return for (let i = 0; i < array.length; i++) { fn(array[i]) } } const forEachArr = [1, 3, 6, 8, 9]; forEach(forEachArr, function(item) { console.log(item) }) 复制代码
// 模拟过滤函数filter function filter(array, fn) { if (Object.prototype.toString.call(array) !== '[object Array]' || typeof fn !== "function") return let res = [] // 存储满足条件的数据 for (let i = 0; i < array.length; i++) { let item = array[i] if (fn(item)) { res.push(item) } } return res } const filterArr = [1, 3, 6, 8 ,9] // 过滤数组中的偶数 const evenNumbers = filter(filterArr, function(item) { return item % 2 === 0 }) 复制代码
以上两个例子我们可以看出:当函数作为参数时调用会更灵活,在使用某个功能时不需要考虑其内部是如何去实现,也达到了功能封装的效果
函数作为返回值使用
函数作为返回值,即当我们去调用一个函数的时候,该函数会给我们返回一个Function类型的数据 示例:高阶函数-函数作为返回值
function makeFn() { if (Object.prototype.toString.call(array) !== '[object Array]' || typeof fn !== "function") return let msg = 'Hello function' return function() { console.log(msg) } } // 调用makeFn得到return返回的函数 const fn = makeFn() // 执行fn fn() // 也可以使用连续执行 makeFn()() 复制代码
// 模拟once函数 function once(fn) { if (Object.prototype.toString.call(array) !== '[object Array]' || typeof fn !== "function") return let done = false // 标记当前函数是否被执行 return function() { if (!done) { console.log('>>', arguments) done = true // 返回函数执行结果 return fn.apply(this, arguments) } } } // 模拟支付场景 const pay = once(function(money) { console.log('支付:${money}') }) pay(10) // 执行 // 之后的都不会执行 pay(10) pay(10) 复制代码
为什么要使用高阶函数(使用高阶函数的意义)
- 高阶函数是用来抽象通用问题的
- 抽象可以帮我们屏蔽细节,只需要关注我们的目标
- 使代码更简洁
举例:比如我们现在需要去遍历一个数组,按照面向过程的方式时我们需要使用一个for循环,定义一个循环变量,判断循环条件等操作;如果此时我们使用高阶函数对遍历这个步骤进行抽象,如上边实现的forEach函数,我们此时只需要知道forEach内部帮我们实现了循环,然后传递数据给forEach。(前边的filter函数也是如此)
常用的高阶函数
- forEach
- map
- filter
- every
- some
- find/findIndex
- reduce
- sort
- ......
map实现
// 此处我们使用ES6中的箭头函数来实现 const map = (array, fn) => { if (Object.prototype.toString.call(array) !== '[object Array]' || typeof fn !== "function") return let res = [] // 此处我们使用for循环的替代for of来实现 for (let value of array) { res.push(fn(value)) } return res } const mapArr = [1, 2, 3, 4] // 此处我们来对数组中的元素做平方运算 const squareArr = map(mapArr, value => value * value) console.log(squareArr) 复制代码
some实现(检测数组中的元素是否至少有一个满足某个条件)
const some = (array, fn) => { if (Object.prototype.toString.call(array) !== '[object Array]' || typeof fn !== "function") return let res = false for (let value of array) { res = fn(value) if (res) { break } } return res } const someArr = [1, 3, 4, 5] // 判断数组中是否有偶数 const hasEvenNumber = some(someArr, value => value % 2 == 0) console.log(hasEvenNumber) 复制代码
every实现(判断数组中的每一个元素是否都匹配某个条件)
const every = (array, fn) => { if (Object.prototype.toString.call(array) !== '[object Array]' || typeof fn !== "function") return let res = true // 用于记录数组中的元素是否匹配 for (let value of array) { res = fn(value) if (!res) break } return res } const everyArr = null // 判断数组中每一个元素是否大于10 const moreThenTen = every(everyArr, value => value > 10) console.log(moreThenTen) 复制代码
这篇关于JavaScript中的函数式编程--函数的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-12-30Sentinel限流教程:新手入门指南
- 2024-12-30Springboot框架教程:新手入门及初级技巧
- 2024-12-30Springboot框架教程:初学者必看指南
- 2024-12-30Springboot企业级开发教程:从入门到实践
- 2024-12-30Springboot企业级开发教程:新手入门与实践
- 2024-12-30SpringBoot微服务教程:入门与实践
- 2024-12-30SpringBoot项目开发教程:从入门到实践
- 2024-12-30Springboot项目开发教程:从入门到实践
- 2024-12-30SpringCloud Alibaba教程:轻松入门与实践
- 2024-12-30SpringCloud Alibaba教程:入门与实践指南