JavaScript:了解一下函数式编程

一、简介

在JavaScript中,函数就是第一类公民,它可以像字符串、数字等变量一样,使用var修饰并作为数据使用。它可以作为数值、可以作为参数、还可以作为返回结果。可以说JavaScript就是函数式编程。ES6新语言特性中,箭头函数、扩展运算符会极大地帮助开发者利用函数式编程技术进行开发。

 //定义一个箭头函数
 var print = (message) => console.log(message)

1、函数作为数值使用

 //将函数作为数值使用
 const array = ["XYQ",print]
 console.log(array) //["XYQ", function] (2)

2、函数作为参数使用

 //将函数作为参数使用
 //定义一个函数lg,它接收一个参数logger函数,lg的函数体内部会执行这个参数logger函数
 //由于传入的print函数可以接收一个参数,所以logger函数在执行时,默认传入了一个字符串
 const lg = logger => logger("I Am XYQ")
 lg(print) //I Am XYQ

3、函数作为返回值使用

 //将函数作为返回值使用
 //定一个函数fcVale,它接收一个logger函数,同时它的返回值为新的函数,新的函数可以传入
 //一个变量进行打印。最终,用函数fcVale创建一个函数fc,并给fc函数传入字符串进行调用
 // var fcVale = function (logger) {
 //     return (message) => logger(message.toUpperCase())
 // }
 const fcVale = logger => message => logger(message.toUpperCase()) //高阶函数, 函数既可以接收函数参数,也可以作为其他函数返回值
 const fc = fcVale(print)
 fc("i am xyq") //I AM XYQ

二、风格

在JavaScript开发中,对于函数的编程分为两种风格,分别是命令式和声明式,其中函数式编程就是声明式的一部分。所谓命令式,就是更加重视函数为达到目标的执行过程而不是结果,也即重执行轻结果。而声明式,则恰恰相反,对执行结果的描述远胜于执行过程,声明式的函数很容易理解它的用途是什么,至于具体的执行细节则被隐藏了。在JavaScript中,声明式函数的编程使用及其广泛。

 //定义一个字符串变量
 var userString = "My Name is XYQ"

1、命令式

 //命令式:遍历字符串,将字符串的空格全部用下划线替换 【开发者必须看完这个代码快才能知道函数的作用是替换功能】
 var temp = ""
 for (var i=0; i<userString.length; i++){
    if (userString[i] === " "){
         temp += "_"
    } else {
         temp += userString[i]
    }
 }
 console.log(temp) //My_Name_is_XYQ

2、声明式

 //声明式:使用正则表达式,将字符串的空格全部用下划线替换 【开发者看到replace就基本知道函数的用途就是替换功能】
 const user_string = userString.replace(/ /g,"_")
 console.log(user_string) //My_Name_is_XYQ

三、概念

函数式编程是JavaScript中的核心功能,它的核心概念一共有四种,分别是不可变性、纯函数、数据转换、高阶函数以及递归。

1、不可变性,说的是在函数式编程中,数据是不可以改变的,他们永远无法修改,实现不可变的工作机制就是对原生数据进行拷贝编辑,然后取代使用。

<script type="text/javascript">
     //定义一个person对象
   var person = {
       name: "XYQ",
       age: 25,
       sex: "male"
   }

   //方法一:通过Obejct.assign方法拷贝机制,创建一个空白对象,并将当前对象拷贝到空白对象上,接着重写对象值
   var copyPerson = function (person, name) {
       return Object.assign({}, person, {name:name}) // {} 为一个空白对象, person拷贝到{}上,重写name值
   }
   var newPerson = copyPerson(person,"YPX")
   console.log(newPerson.name) //YPX
   console.log(person.name)    //XYQ,可以看到原对象没有发生改变

   //方法二:通过扩展运算符特性对对象进行拷贝
   const copyPerson2 = (person, name) => ({
       ...person,
       name
   })
   var newPerson2 = copyPerson(person,"YPX")
   console.log(newPerson2.name)  //YPX
   console.log(person.name)      //XYQ,可以看到原对象没有发生改变

   //---------------------------------------------------------------------------------//

   //定义一个数组对象
   var persons = [
       {name:"XYQ"},
       {name:"YPX"}
   ]

   //方法一:使用数组的Array.concat方式将数组串联起来,生成一个新的对象并添加原生数组的副本上,不可以用Array.push这个可变函数
   const addPerson = (name, persons) => persons.concat({name})
   var newPersons = addPerson("HXF", persons)
   console.log(newPersons) //[{name: "XYQ"}, {name: "YPX"}, {name: "HXF"}] (3)
   console.log(persons)    //[{name: "XYQ"}, {name: "YPX"}] (2),可以看到原数组没有发生改变

   //方式二:使用扩展运算法特性对数组进行拷贝
   const addPerson2 = (name, persons) => [...persons, {name}]
   var newPersons2 = addPerson2("HXF", persons)
   console.log(newPersons2) //[{name: "XYQ"}, {name: "YPX"}, {name: "HXF"}] (3)
   console.log(persons)     //[{name: "XYQ"}, {name: "YPX"}] (2),可以看到原数组没有发生改变
</script>

2、纯函数,是一个返回结果只依赖输入参数的函数,它至少需要接收一个参数并且总是返回一个值或者其他函数,它把参数当做不可变数据使用,不做任何修改。

纯函数特点:
1、函数应该至少接收一个参数;
2、函数应该返回一个值或者其他函数;
3、函数不应该修改或者影响任何传给它的参数
<script type="text/javascript">

  //定义一个person对象
  var person = {
      name: "XYQ",
      age: 25,
      sex: "male"
  }

  //创建一个纯函数,返回值是根据参数preson生成的一个新的person,它没有改变参数person,更改的返回的新的person。
  const updatePerson = person => ({
      ...person,
      name:"YPX",
      sex:"feMale"
  })

  //打印
  var newPerson = updatePerson(person)
  console.log(newPerson) // {name: "YPX", age: 25, sex: "feMale"}
  console.log(person)    // {name: "XYQ", age: 25, sex: "male"}, 原对象person没有发生改变

</script>

3、数据转换,函数式编程中由于数据的不可变性,它会将一种数据转换成另一种数据,使用函数生成转换后的副本进行状态的转换。

 //定义一个city数组
 const cities = ["BeiJing","ChongQing","ChongDu"]

 //使用系统函数Array.join()将数组用分隔符连接成字符串
 var cityString = cities.join(",")
 console.log(cityString) // BeiJing,ChongQing,ChongDu
 console.log(cities)     // ["BeiJing", "ChongQing", "ChongDu"] (5)

 //使用系统函数Array.filter()进行谓词过滤,这个谓词始终是一个返回布尔值的函数
 //会访问数组每一个元素,匹配C开头的城市,如果返回true,则将其添加到新的数组中
 const newCities = cities.filter(city => city[0] === "C")
 console.log(newCities) // ["ChongQing", "ChongDu"] (2)
 console.log(cities)    // ["BeiJing", "ChongQing", "ChongDu"] (5)

 //仍然使用系统函数Array.filter(),代替Array.pop()和Array.splice()函数删除元素。因为后面的两个方法是可变的。
 const deleteCity = (deletedCity, cities) => cities.filter(city => city !==    deletedCity)
 const newCities2 = deleteCity("BeiJing", cities)
 console.log(newCities2) // [ "ChongQing", "ChongDu"] (4)
 console.log(cities)     // ["BeiJing","ChongQing", "ChongDu"] (5)

 //使用系统函数Array.map(),参数也是一个函数,在函数在访问数组中每一个元素时会执行
 const  newCities3 = cities.map(city => `${city} China`)
 console.log(newCities3) // ["BeiJing China","ChongQing China", "ChongDu China"] (5)
 console.log(cities) //["BeiJing", "ChongQing", "ChongDu"] (5)

 // 仍然使用系统函数Array.map(),她还可以构造任意对象、数值、数组、函数等
 // 1、将数组转对象
 let objectCities = cities.map(city => ({cityName : city}))
 console.log(objectCities) // [{cityName: "BeiJing"}, {cityName: "ChongQing"}, {cityName: "ChongDu"}] (3)
 console.log(cities) // ["BeiJing", "ChongQing", "ChongDu"] (3)

 // 2、修改对象元素
 const updateCityName = (originCityName, cityName, cities) =>
            (cities.map(city => (city.cityName === originCityName) ? ({...city, cityName}) : city))
 const newObjectCities = updateCityName("BeiJing","TianJin",objectCities)
 console.log(objectCities) //[{cityName: "BeiJing"}, {cityName: "ChongQing"}, {cityName: "ChongDu"}] (3)
 console.log(newObjectCities) //[{cityName: "TianJin"}, {cityName: "ChongQing"}, {cityName: "ChongDu"}] (3)

 // 3、将对象转数组(配合Object.key函数使用)
 //定义一个city对象
 const cityObject = {"BeiJing":"China","NewYork":"USA"}
 const cityObjects = Object.keys(cityObject).map(key =>
     ({cityName: key, country: cityObject[key]})
 )
 console.log(cityObject) //{BeiJing: "China", NewYork: "USA"}
 console.log(cityObjects)//[{cityName: "BeiJing", country: "China"}, {cityName:  "NewYork", country: "USA"}](2)

 // 系统函数Array.reduce()和rArray.reduceRight()可以用来将数组转成任意值,比如数字、字符串、布尔值、对象甚至函数
 // Array.reduce()函数, 从数组头部开始处理元素 ; Array.reduceRight()函数,从数组尾部 开始处理元素
 // 求最值
 const nums = [10,5,30,24,78,60,100]
 const max = nums.reduce((max, num) => (num > max) ? num : max)
 const min = nums.reduce((min, num) => (num < min) ? num : min)
 console.log(max) // 100
 console.log(min) // 5

 // 去重,items为新的空数组
 const names = ["XYQ","YPX","XXF","XYQ","XYQ"]
 const deletedNames = names.reduce((items, name)=> items.indexOf(name) !== -1 ? items : [...items,name], [])
 console.log(names) //["XYQ", "YPX", "XXF", "XYQ", "XYQ"] (5)
 console.log(deletedNames) //["XYQ", "YPX", "XXF"] (3)

4、高阶函数,是可以操作其他函数的函数,它们可以将函数当做参数传递,也可以返回一个函数,或者二者兼有之。柯里化就是典型的应用。

 //定义高阶函数,把函数当做参数
 const printer = () => console.log("---printer---")
 const logger  = () => console.log("---logger---")
 const show = (selectPrint, printer, logger) => (selectPrint) ? printer() : logger()

 //调用高阶函数
 show(true,printer,logger)  //---printer---
 show(false,printer,logger) //---logger---

 //定义高阶函数,把函数当做返回值
 const log = (message) =>( () => console.log(message) )
 const logFunction = log("I Am XYQ")

 //调用高阶函数
 logFunction() //I Am XYQ

5、递归,它是用户创建的函数调用自身的一种技术方案,在开发中遇到循环时,通过递归可以极其精简的缩短代码量,是一种优势替代方案。

 //定义一个倒序遍历的函数
 const countDown = (number, log) => {
      log(number)
      return (number > 0) ? countDown(number-1, log) : number
 }

 //调用递归函数
 const log = (number) => console.log(number)
 countDown(5,log)// 5 4 3 2 1 0

、链式

函数式编程是将具体的业务逻辑拆分成一个个小型的简单的纯函数,方便进行功能聚焦,最终,开发者通过串联或者并联的方式将这些小型函数合成在一起进行调用即可。这个合成的过程其实就是链式调用。如之前介绍的Promise对象的应用。

 //使用系统函数replace实现链式调用
 const formmater = "hh:mm:ss tt"
 const currentTime = formmater.replace("hh", "22").replace("mm","07").replace("ss","00").replace("tt","PM")
 console.log(currentTime) //22:07:00 PM

原文地址:https://www.cnblogs.com/XYQ-208910/p/11965612.html

时间: 2024-08-04 09:40:59

JavaScript:了解一下函数式编程的相关文章

JS函数式编程【译】4.在Javascript中实现函数式编程的技术

?? Functional Programming in Javascript 主目录上一章 建立函数式编程环境 第四章 在Javascript中实现函数式编程的技术 扶好你的帽子,我们现在要真正进入函数式的思想了. 这章我们继续下面的内容: 把所有的核心概念放到一个集中的范式里 探索函数式编程之美 一步步跟踪函数式模式相互交织的逻辑 我们将贯穿整章建立一个简单的应用做一些很酷的事情 你可能已经注意到,在上一章我们介绍Javascript的函数式库的时候引入了一些概念, 而不是在第二章<函数式编

javascript - Underscore 与 函数式编程

<Javascript函数式编程 PDF> # csdn下载地址http://download.csdn.net/detail/tssxm/9713727 Underscore # githubhttps://github.com/jashkenas/underscore # 中文官方网站http://www.css88.com/doc/underscore/ # CDN<script src="https://cdn.bootcss.com/underscore.js/1.8

Javascript 中的函数式编程

本文和大家分享的主要是javascript中函数式编程相关内容,一起来看看吧,希望对大家学习javascript有所帮助. 函数式编程(functional programming)或称函数程序设计,又称泛函编程,是一种编程范型,比起命令式编程,函数式编程更加强调程序执行的结果而非执行的过程,倡导利用若干简单的执行单元让计算结果不断渐进,逐层推导复杂的运算,而不是设计一个复杂的执行过程. 函数式编程,近年来一直被炒得火热,国内外的开发者好像都在议论和提倡这种编程范式.在众多的函数式语言中,Jav

JavaScript系列:函数式编程(开篇)

前言: 上一篇介绍了 函数回调,高阶函数以及函数柯里化等高级函数应用,同时,因为正在学习JavaScript·函数式编程,想整理一下函数式编程中,对于我们日常比较有用的部分. 为什么函数式编程很重要? 学习过C++,java这些面向对象编程语言,我们大概都知道面向对象编程就是把目标问题分成几个部分,实现各部分的功能,再组合成一个更强大的对象.虽说JavaScript不是面向对象编程语言(虽然ES6已经出现了Class类这种对象,在此暂且不说),但它却是一种完完全全支持函数式编程的语言,利用函数式

给 JavaScript 开发者讲讲函数式编程

本文译自:Functional Programming for JavaScript People 和大多数人一样,我在几个月前听到了很多关于函数式编程的东西,不过并没有更深入的了解.于我而言,可能只是一个流行词罢了.从那时起,我开始更深地了解函数式编程并且我觉得应该为那些总能听到它但不知道究竟是什么的新人做一点事情. 谈及函数式编程,你可能会想到它们:Haskell 和 Lisp,以及很多关于哪个更好的讨论.尽管它们都是函数式语言,不过的确有很大的不同,可以说各有各的卖点.在文章的结尾处,我希

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

用函数式编程技术编写优美的 JavaScript_ibm作者: 字体:[增加 减小] 类型:转载函数式编程语言在学术领域已经存在相当长一段时间了,但是从历史上看,它们没有丰富的工具和库可供使用.随着 .NET 平台上的 Haskell 的出现,函数式编程变得更加流行.一些传统的编程语言,例如 C++ 和 JavaScript,引入了由函数式编程提供的一些构造和特性.在许多情况下,JavaScript 的重复代码导致了一些拙劣的编码.如果使用函数式编程,就可以避免这些问题.此外,可以利用函数式编程

JS函数式编程 3.1 Javascript的函数式库

?? Functional Programming in Javascript 主目录第三章 建立函数式编程环境 Javascript的函数式库 据说所有的函数式程序员都会写自己的函数库,函数式Javascript程序员也不例外. 随着如今开源代码分享平台如GitHab.Bower和NPM的涌现,对这些函数库进行分享.变得及补充变得越来越容易. 现在已经有很多Javascript的函数式变成苦,从小巧的工具集到庞大的模块库都有. 每一个库都宣扬着自己的函数式编程风格.从一本正经的数学风格到灵活松

JavaScript中函数式编程中文翻译

原著由 Dan Mantyla 编写 近几年来,随着 Haskell.Scala.Clojure 等学院派原生支持函数式编程的偏门语言越来越受到关注,同时主流的 Java.JavaScript.Python 甚至 C++都陆续支持函数式编程.特别值得一提的是,在 nodejs 出现后,JavaScript 成为第一种从前端到后台的全栈语言,而且 JavaScript 支持多范式编程.应用函数式编程的最大挑战就是思维模式的改变———从传统面向对象的范式变为函数式编程范式. <JavaScript

JavaScript函数式编程(1):基本思想

1 函数式编程简介 函数式编程是和传统命令式编程区分的一种编程思想,"在函数式编程语言中,函数是第一类的对象,也就是说,函数 不依赖于任何其他的对象而可以独立存在,而在面向对象的语言中,函数 ( 方法 ) 是依附于对象的,属于对象的一部分.这一点决定了函数在函数式语言中的一些特别的性质,比如作为传出 / 传入参数,作为一个普通的变量等.[1]" 函数式编程思想的源头可以追溯到 20 世纪 30 年代,数学家阿隆左 . 丘奇在进行一项关于问题的可计算性的研究,也就是后来的 lambda

[原创译书] JS函数式编程 第二章总结

?? Functional Programming in Javascript 主目录第二章 函数式编程基础上一节 函数式程序员的工具集 第二章总结 为了理解函数式编程,这章覆盖了很大范围的主题.首先我们分析了一个编程语言的函数式是什么意思, 并且评估了Javascript函数式编程能力.接下来,我们用Javascript实现了一些函数式编程的核心概念, 并展示了一些Javascript内建的函数式编程函数. 尽管Javascript有一些函数式编程的工具,它函数式编程核心的大部分仍被隐藏着,并