函数式编程发端于上个世纪五十年代,最初用于lambda语言的演算。其理念是一切皆函数,由一大堆一元或二元参数的函数拼装而成,每一个函数通常只作一件事情。这种设计思想摈弃了过程式、命令式等编程理念的做法,重在以抽象的方式封装诸多处理单一问题的函数,然后再将封装的函数组合起来,最后产生所期待的结果。
函数式编程的每一个函数都是纯函数,它不依赖外部变量,不受全局变量的影响,仅仅通过传参来计算并返回运行结果。在JS中,随着JS的不断迭代,函数式编程也得到了广泛使用。这里,为了理解纯函数,我们以随机生成 rgb 颜色为例,看看JS如何通过纯函数去实现。
在具体实现之前,我们有必要先简单了解一下 rgb 颜色表达体系的特征:r 代表 red 即红色,g 代表 green 即绿色,b 代表 blue 即蓝色,三种颜色以不同的比例混合在一起就能构成一种新的颜色。每一种源颜色的取值范围是 0~255,例如,rgba(255, 103, 0) 就构成了前面 rgb 表达结构文本这样的颜色。
现在可以开干了。我们首先需要设计一个函数,用来生成 0~255 的随机数。按照函数式编程的准则之一,一元化参数,它尽可能只接收一个传参,那我们试着这样编写:
var getRanNum = (n) => Math.random() * n;
getRanNum(n) 需要调用者传来一个参数 n,n 将在 0~255 范围内取值,但如果用在别处而非生成 rgb 随机颜色也可以不受此限制,即便用在 rgb 颜色它也拥有较高的自由度:使用者可以设定 rgb 中任意一个三原色成分的下限以便获得定制性更强的随机颜色。可见其复用性是很广泛的。
getRanNum(n) 函数能生成一个随机数,但它是一个浮点数,小数点后面的数字好长,我们需要加工一下:
var getRanNum = (n) => Math.round(Math.random() * n);
其实就是将运算结果取整,Math.round 是四舍五入的数学方法。
接下来我们要用 getRanNum(n) 函数生成三个随机数,并按照 rgb(R,G,B) 这样的语句结构将生成的结果拼装起来。
var mkRgb = (ar) => `rgb(${ar.map(item => getRanNum(item))})`;
mkRgb(ar) 函数也是一个纯函数,它接收一个传参 ar,顾名思义是一个数组,数组结构类似这样,[255,100,200],可以根据需要改变数组元素个数和里面的元素数值。函数比较抽象,这里解释一下:我们用JS内置的 map 函数迭代数组,将其数组元素值一个一个地作为传参 n 传给前面写好的函数 getRanNum(n) 进行处理并返回处理结果——这将得到一个新的数组,而数组元素天然使用了小角逗号将数组元素连结起来,正好符合 rgb 颜色表达结构的要求。至于拼装 rgb 语句结构的其它字符,我们使用反引号 `` 就非常省事了,无需多写哪怕半行的代码——代码中红色的部分就是 rgb() 语句框架,美元符号加花括号内的语句是生成随机数的程序语句。
以下实例使用上述原理完成。每次点击元素界面任意处,均会产生随机 rgb 颜色,元素背景色即为当次点击所产生的颜色,颜色值出现在元素的正中央:
实例代码:
<style>
#mydiv { margin: 20px auto; display: grid; place-items: center; width: 400px; height: 200px; border: 1px solid gray; position: relative; }
#outMsg { padding: 10px 20px; background: white; width: fit-content; border-radius: 20px; }
</style>
<div id="mydiv"><p id="outMsg"></p></div>
<script>
var getRanNum = (n) => Math.round(Math.random() * n);
var mkRgb = (ar) => `rgb(${ar.map(item => getRanNum(item))})`;
mydiv.onclick = () => outMsg.textContent = mydiv.style.background = mkRgb([255,255,255]);
mydiv.click();
</script>