资讯专栏INFORMATION COLUMN

Redux概念之四: reducer(归纳函数)与纯函数

wangjuntytl / 1603人阅读

摘要:函数的区分是以纯函数与不纯函数两者来区分,但这不光只有无副作用的差异,还有其他的条件。现在已经有一些新式的函数库或框架例如,会特别强制要求在某些地方只能使用纯函数,而具有副作用的不纯函数只能在特定的情况下才能使用。

reducer(归纳函数)

reducer(归纳函数)这种函数的名称,是由数组的一个迭代方法reduce(归纳)而来,你可以参考MDN中的相关说明:

在JS语言中的数组reduce(归纳)这个方法是一种应用于特殊情况的迭代方法,它可以藉由一个回调(callback)函数,来作前后值两相运算,然后不断缩减数组中的成员数量,最终返回一个值。reduce(归纳)并不会更动作为传入的数组(调用reduce的数组),所以它也没有副作用。一个简单的例子如下:

const aArray = [0, 1, 2, 3, 4, 5]

const sum = aArray.reduce(function(pValue, value, index, array){
    return pValue + value
})

console.log(sum) // 15

数组的reduce(归纳)方法,还有另一种语法样式,是带有初始值的,这会比较接近Redux中的reducer样式,如下面的例子:

const initialState = 0

const sum = [1, 2, 3, 4, 5].reduce(add, initialState)

function add(a, b) {
    // `a` 代表前一个状态
    // `b` 代表目前在数组中的项目
    return a + b
}

console.log(sum) // 15

reduce(归纳)方法具有分散运算的特点,常见于下面几种应用之中:

两相比较最后取出特定的值(最大或最小值)

计算所有成员(值),总合或相乘

其它需要两两处理的情况(组合巢状数组等等)

不过,Redux中的reducer与数组中的reduce方法并不相同,其中最大的差异,是reducer并不是对一整个列表进行归纳运算,而是对一个action(动作)与目前的state进行归纳运算,回传出新的state。

副作用与纯函数

当一个函数是纯函数时,我们可以说输出只取决于输入

对于函数来说,具有副作用代表着可能会更动到外部环境,或是更动到传入的参数值。函数的区分是以 纯(pure)函数 与 不纯(impure)函数 两者来区分,但这不光只有无副作用的差异,还有其他的条件。纯函数(pure function)即满足以下三个条件的函数,以下的定义是来自于Redux的概念:

给定相同的输入(传入值),一定会返回相同输出值结果(返回值)

不会产生副作用

不依赖任何外部的状态

一个典型的纯函数的例子如下:

const sum = function(value1, value2) {
  return value1 + value2
}

套用上面说的条件定义,你可以用下面观察来理解它是不是一个纯函数:

只要每次给定相同的输入值,就一定会得到相同的输出值: 例如传入1与2,就一定会得到3

不会改变原始输入参数,或是外部的环境,所以没有副作用

不依頼其他外部的状态,变量或常量

那什么又是一个不纯的函数?看以下的例子就是,它需要依赖外部的状态/变量值:

let count = 1

let increaseAge = function(value) {
  return count += value
}

在JavaScript中不纯函数很常见,像我们一直用来作为输出的console.log函数,或是你可能会在很多例子看到的alert函数,都是"不"纯函数,这类函数通常没有返回值,都是用来作某件事,像console.log会更动浏览器的主控台(外部环境)的输出,也算是一种副作用。

每次输出值都不同的不纯函数一类,最典型的就是Math.random,这是产生随机值的内建函数,既然是随机值当然每次运行的返回值都不一样。

例如在数组的内建方法中,有一些是有副作用,而有一些是无副作用的,这个部份需要查对应API才能够清楚。不会改变传入的数组的,会在作完某件事后返回一个新数组的方法,就是无副作用的纯函数(方法),而会改变原数组就算是不纯函数(方法)了。

下面是两个在数组中作同样事情的不同方法,都是要取出只包含数组的前三个成员的数组。一个用splice,另一用是slice,看起来都很像,连这两个方法的名称都很像,但却是完全属于不同的种类:

// 不纯粹(impure),splice会改变到原数组
const firstThree = function(arr) {
  return arr.splice(0,3)
}

// 纯粹(pure),slice会返回新数组
const firstThree = function(arr) {
  return arr.slice(0,3)
}

其他有许多内建的或常用的函数都是免不了有副作用的,例如这些应用:

会改变传参(对象、数组)的函数(方法)

时间性质的函数,setTimeout等等

I/O相关

数据库相关

AJAX

纯函数当然有它的特别的优点:

代码阅读性提高

较为封闭与固定,可重覆使用性高

输出输入单纯,易于测试、调试

因为输入->输出结果固定,可以缓存或作记忆处理,在高花费的应用中可作提高运行效率的机制

最后,并不是说有副作用的函数就不要使用,而且要很清楚的理解这个概念,然后尽可能在你自己的撰写的一般功能函数上使用纯函数,以及让必要有副作用的函数得到良好的管控。现在已经有一些新式的函数库或框架(例如Redux),会特别强制要求在某些地方只能使用纯函数,而具有副作用的不纯函数只能在特定的情况下才能使用。

注: 虽然在副作用与纯函数的介绍中,我们有提到一些调用外部API(console.log/alert)、时间(Date())、随机(Math.random)也属于有副作用的调用,但以等级来区分它们只算是"轻度"或"微量"的副作用,这些在reducer或Action Creators能不能用?答案是可以用但也不要用,它会影响到纯函数的一些优化。以在副作用的主题来说,异步运行才是"中度"或"一般"等级的副作用,我们谈到副作用通常是指这个等级的。当然也有"重度"等级的副作用,那是另一个层次的特殊应用情况讨论,例如组合出来的复杂异步运行流程结构。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/81348.html

相关文章

  • React 可视化开发工具 Shadow Widget 非正经入门(之四:flux、mvc、mvvm

    摘要:是分发器,是数据与逻辑处理器,会在注册针对各个命令字的响应回调函数。当按如下方式触发回调时,回调函数具备事件的特性。 本系列博文从 Shadow Widget 作者的视角,解释该框架的设计要点。本篇解释 Shadow Widget 在 MVC、MVVM、Flux 框架之间如何做选择。 showImg(https://segmentfault.com/img/bVOODj?w=380&h...

    msup 评论0 收藏0
  • Redux概念之二: Redux的三大原则

    摘要:就是应用程序领域的状态,它是类型中的模型的设计的概念,这设计是由架构而来的,在原本的架构中是允许多个的结构,简化为只有单一个。的设计中是与中的相比,它们之间有一些类似的设计。 Redux里的强硬规则与设计不少,大部份都会与FP(函数式程序开发)、改进原本的Flux架构设计有关。Redux官网文档上的三大基本原则,主要是因为有可能怕初学者不理解Redux中的一些限制或设计,所以先写出来说...

    dingda 评论0 收藏0
  • redux源码分析之二:combineReducers.js

    摘要:欢迎关注源码分析系列文章源码分析之一源码分析之二源码分析之三源码分析之四源码分析之五文件对外暴露了一个函数,函数是的一个辅助性的函数,用于拆分里面的第一个参数函数。函数的返回值是一个函数,该函数是组合之后的一个标准的函数。 欢迎关注redux源码分析系列文章:redux源码分析之一:createStore.jsredux源码分析之二:combineReducers.jsredux源码分...

    big_cat 评论0 收藏0
  • redux源码分析之一:createStore.js

    摘要:定义了几个函数用于修改上面的几个局部变量主要包括函数用于获取用于替换用于修改列表用于触发执行,生成新的,并且,执行列表中的每一个函数完整解析请参考我的,如果对您有帮助,欢迎,有任何问题也请指正。 欢迎关注redux源码分析系列文章:redux源码分析之一:createStore.jsredux源码分析之二:combineReducers.jsredux源码分析之三:bindAction...

    NotFound 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<