ReactJS开发笔记

函数式编程

2019-07-17  本文已影响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中,两个核心函数需要用到:

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.

上一篇下一篇

猜你喜欢

热点阅读