为了账号安全,请及时绑定邮箱和手机立即绑定

React前奏,函数式编程基本概念

标签:
React.JS

函数式编程基本概念

  • 写在之前,这些内容参考自O`REILLY系列图书《React学习手册》

  • 在React中,UI是用纯函数表示的,并且在构造DOM时,是以声明式(与此相对的,是命令式)的方式。而声明式的编程是函数式编程更广义的一部分。所以,先熟悉函数式的编程,很有必要。

结合了如下所述,我发现了es6中数组的新语法,    像mapfilterreduce这些,都满足了不可变性,数据转换,纯函数,高阶函数等要点,很精髓。

1,不可变性

  • 数据在应用程序中,在不改变原生数据结构的前提下,在此基础上拷贝后进行编辑。

  • 在此基础上,就会有浅拷贝和深拷贝的选择。

比如,在原有对象上添加属性,而不影响原对象

let person = {   name: 'Beckham',   age: 33 } let player = (person, sex) => ({   ...person,   sex }) console.log(person) console.log(player(person, 'male'))

2,纯函数

结果只依赖输入参数

  • 函数至少接收一个参数

  • 返回一个值或其他函数

  • 不应该修改或影响传递给它的参数

  • 不会产生副作用,比如修改了全局变量,影响了程序的状态

3,数据转换

3.1,定义

  • 从其他数据源创建一个新的数据集。

3.2,作用

  • 为了使用转换后的副本

所以,mapfilterreduce这些函数都是必不可少的。

  • 基本用法

对象转为数组

let country = {   "beijing": 10,   "shanghai": 6,   "shenzhen": 9 } let obj = Object.keys(country).map(key =>  ({   name: key,   value: country[key] }) ) console.log(obj)

数组中,寻找最大值

let ages = [11,66,33,22,11,55] let maxAge = ages.reduce((max, age) => { if (max > age) {   return max } else {   return age } }, 0) console.log(maxAge)

数组去重,思路:有的话不变,没有的话添加。

let colors = ['red','green','blue','red','green','blue'] const distinctColor = colors.reduce((distinct, color) => (   (distinct.indexOf(color) !== -1) ? distinct : [...distinct, color] ), [] ) console.log(distinctColor)

4,高阶函数

  • 定义:将函数作为参数传递,或返回一个函数

所以,数组的mapfilterreduce都是高阶函数

5,递归

  • 目的:在涉及到循环时,递归可提供一种替代性的方案

  • 在浏览器的调用堆栈中,会依次放入当前执行的函数,在出栈时,后进先出。

打印输出10~0

let countDown = (count, fn) => {   fn(count)   return (count > 0) ? countDown(count-1, fn) : count } countDown(10, count => console.log(count))

倒计时输出10~0

let countDown = (count, fn, delay = 1000) => {   fn(count)   return (count > 0) ? setTimeout(() => countDown(count-1, fn), delay) : count } countDown(10, count => console.log(count))

6,合成

6.1 定义

  • 将具体的业务逻辑拆解为小型纯函数,用户会在特定条件下合成它们,以串联或并联的方式进行调用。

6.2 目标

  • 通过整合若干简单函数,构造一个更高阶的函数

链式调用,就是合成技术之一

let template = 'hh:mm:ss tt' let clockTime = template.replace('hh','09')   .replace('mm','06')   .replace('ss', '52')   .replace('tt', 'PM') console.log(clockTime)  // 09:06:52 PM

7,综上应用

  • 获取当前时间,实现实时时钟。

// 计时器时间 const oneSecond = () => 1000 // 获取当前时间 const getCurrentTime = () => new Date() // 清除控制台输出 const clear = () => console.clear() // 控制台打印内容 const log = message => console.log(message) // 构造一个时钟对象,包含时分秒 const abstractClockTime = date =>     ({         hours: date.getHours(),         minutes: date.getMinutes(),         seconds: date.getSeconds()     }) // 接收一个时钟对象, // 该方法用于指定12小时制 const civilianHours = clockTime =>     ({         ...clockTime,         hours: (clockTime.hours > 12) ? clockTime.hours - 12 : clockTime.hours     }) // 接收一个时钟对象 // 该方法用于,为时钟对象添加一个属性,用于表示am 或 pm const appendAMPM = clockTime =>     ({         ...clockTime,         ampm: (clockTime.hours >= 12) ? "PM" : "AM"     }) /* * @target 目标函数(本例中就是log函数) * @time 时钟对象 * 返回的函数,会将时间发送给目标函数 * */ const display = target => time => target(time) /* * @format 模板字符串 "hh:mm:ss:tt" * @time 时钟对象 * 返回的函数,将时间进行格式化 * */ const formatClock = format =>     time =>         format.replace("hh", time.hours)             .replace("mm", time.minutes)             .replace("ss", time.seconds)             .replace("tt", time.ampm) /* * @key 时钟对象的属性 * @clockTime 时钟对象 * 返回的函数,将时钟对象的属性,包括时分秒,当<10时,加0 * */ const prependZero = key => clockTime =>     ({         ...clockTime,         [key]: (clockTime[key] < 10) ? "0" + clockTime[key] : clockTime[key]     }) /* * 接收参数为多个函数,返回一个独立的函数 *   compose函数被调用,返回的独立函数进行调用时,如果不传参, *   就以arg作为reduce的起始值,arg在使用时是undefined, *   而一个函数在定义时,如果没有设置形参,该函数在调用时,传递的参数无效。 *   在这个栗子中,...fns为多个函数组成的数组。 * * 也就是说,arg作为第一个函数的参数,如果该函数定义时没有指定形参,arg将被忽略, * 第一个函数执行的结果,作为第二个函数执行的参数,依次类推。 * */ const compose = (...fns) =>     (arg) =>         fns.reduce(             (composed, f) => f(composed),             arg         ) const convertToCivilianTime = clockTime =>     compose(         appendAMPM,         civilianHours     )(clockTime) const doubleDigits = civilianTime =>     compose(         prependZero("hours"),         prependZero("minutes"),         prependZero("seconds")     )(civilianTime) /* * compose已经被调用了,之后每隔1s,调用一次compose的执行结果 * 注意参与合成的函数的顺序。 * * 清除打印台,获取时间,构造时钟对象,添加am或pm,12小时制,加0,格式化时分秒,发送给打印函数 * */ const startTicking = () =>     setInterval(         compose(             clear,             getCurrentTime,             abstractClockTime,             convertToCivilianTime,             doubleDigits,             formatClock("hh:mm:ss tt"),             display(log)         ),         oneSecond()     ) startTicking()

作者:非梧不栖
链接:https://juejin.im/post/5b30f134e51d4558ca6733d7
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
点击查看更多内容
1人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消