函数式编程

作者: 钢笔先生 | 来源:发表于2019-07-17 01:23 被阅读0次

    Time: 20190716

    函数式编程的概念在JS中随处可见。

    函数可以作为函数的参数进行传递。

    函数就是变量。

    高阶函数:一个以上的箭头表示的是高阶函数。

    示例:

    const createScream = logger => message => logger(message.toUpperCase() + "!!!")
    

    函数是第一类成员,函数就是数据,可以像变量一样被保存、检索或者在程序中传递。

    声明式编程风格

    特点:对执行结果的描述远胜于执行过程。

    命令式编程更关注的是达成目标的具体过程,这种编程风格往往需要辅以大量的注释来解释代码的用途。

    声明式编程风格的代码本身就描述了要做的事情。

    具体到React这里,可以通过对比传统方式和React方式创建DOM的过程来理解:

    // 命令式创建
    var target = document.getElementById("target")
    var wrapper = document.createElement("div")
    var headline = document.createElement("h1")
    
    wrapper.id = "welcome"
    headline.innerText = "Hello World"
    
    wrapper.appendChild(headline)
    target.appendChild(wrapper)
    
    // ReactJS方式
    const { render } = ReactDOM // 解构式
    const Welcome = () => {
      <div id="welcome">
        <h1> Hello World~ </h1>
     </div>
    }
    render(
      <Welcome />, document.getElementById("target")
    )
    

    React采用的是声明式编程风格。

    阅读代码可以看到,React的方式更加易读。

    什么是函数式编程?

    核心概念

    • 不可变性
    • 纯函数
    • 数据转换
    • 高阶函数
    • 递归

    不可变性
    表示,数据永远是不可变的,永远无法修改。

    但是数据经过交互之后的变化是必然的,也意味着我们需要在数据的拷贝上进行编辑,用于取代原生数据。

    let color_lawn = {
      title: "lawn",
      color: "#00F00",
      rating: 4
    }
    

    建立函数用于修改颜色对象的评分:

    function rateColor(color, rating) {
      color.rating = rating
      return color
      console.log(rateColor(color_lawn, 5).rating) // 5
      console.log(color_lawn.rating) // 5
    }
    

    会发现原来的数据也被修改了。

    因为在JS中,函数参数会指向实际的数据。

    比较好的方式是通过使用Object.assign()来实现。

    var rateColor = function(color, rating) {
      return Object.assign({}, color, {rating: rating})
    }
    console.log(rateColor(color_lawn, 5).rating) // 5
    console.log(color_lawn.rating) // 4
    

    Object.assign提供的是一种拷贝机制,提供空白对象,然后将颜色对象拷贝到这个对象上,再重写颜色的评分。

    实现的效果是:不改变原生对象,获得包含新的评分值的新的对象。

    借用ES6规范下的箭头函数来实现的话:

    const rateColor = (color, rating) =>
      ({
        ...color,  // 扩展运算符
        rating
      })
    

    纯函数

    纯函数的含义是:结果只依赖于输入参数的函数。

    纯函数不会产生副作用,不会修改全局变量,或者任何应用程序的状态。

    输入的参数对纯函数而言,是不可变数据。

    纯函数的三个原则

    • 函数至少接收一个参数
    • 函数应该返回一个值或者其他函数
    • 函数不应该修改或者影响任何传递给它的参数

    数据转换

    利用函数式编程,数据是不可变的,为了在程序内部响应状态变化,需要将数据变成另外一种数据,即使用函数生成转换后的副本。

    在JS中,两个核心函数需要用到:

    • Array.map
    • Array.reduce
    const schools = [
      "Yorktown",
      "Washington",
      "Wakefield"
    ]
    
    console.log(schools.join(" , ")) //   "Yorktown, Washington, Wakefield"
    

    Array.join也会从一个数据创建新的数据。

    const wSchools = schools.filter(school => school[0] === 'W')
    console.log(wSchools) // ["Washington", "Wakefield"]
    

    按照指定的布尔函数过滤每个元素,将结果为true的元素值添加到新的数组中。

    另一种变换是Array.map,将每个元素映射到新的元素上。

    const highSchools = schools.map(school => `${school} High School`)
    

    在每个元素后面添加High School

    新的元素不一定非得是相同类型,可以是任何的对象,数值,数组,函数等。

    const highSchools = schools.map(school => ({name: school}))
    

    使用map函数修改对象数组中的某个对象

    let schools = [
      {name: "Yorktown"},
      {name: "Stratford"},
      {name: "Washington"},
      {name: "Wakefield"}
    ]
    
    const editName = (oldName, name, arr) => arr.map(item => {
      if (item.name === oldName) {
        return {
            ...item,
            name
        }
      } else { return item }
    })
    
    let updateSchools = editName("Stratford", "HB Woodlawn", schools)
    
    

    高阶函数

    高阶函数是可以操作其他函数的函数。

    一种是将函数当作参数传递,另一种是返回一个函数,或者二者兼而有之。

    Array.map, Array.filter, Array.reduce都是将函数当作参数传递,这些都是高阶函数。

    合成

    函数式编程会将业务逻辑拆分为小型的纯函数,最终需要将这些小型函数整合到一起。

    或者串联,或者并联调用,合成为更大的函数。

    JS中最常用的是链式调用。

    const template = "hh:mm:ss tt"
    const clockTime = template.replace("hh", "03")
                             .replace("mm", "33")
                             .replace("ss": "33")
                             .replace("tt": "PM")
    

    但链式调用只是一种合成方式,还要其他的方式可供选择。

    合成的目的是明确的:整合若干简单函数构造更高阶的函数。

    END.

    相关文章

      网友评论

        本文标题:函数式编程

        本文链接:https://www.haomeiwen.com/subject/akcflctx.html