编程范式
首先,我先来说说什么是编程范式。编程范式有两种,分别是命令式(Imperative)和声明式(Declarative),命令式强调做的步骤也就是怎么做,而声明式强调做什么本身,以及做的结果。因此,编程语言也可以分成命令式和声明式两种类型。
其实函数式编程是一种声明式的编程范式;
例如:我们要遍历一个数组,将每一个元素的数值翻倍,我们可以分别用命令式和声明式来实现。
- 命令式:
const list = [1, 2, 3, 4];
const map1 = [];
for (let i=0; i<list.length; i++) {
map1.push(list[i] * 2);
}
- 声明式:
const list = [1, 2, 3, 4];
const double = x => x * 2;
list.map(double)
从上面的代码我们可以看到,虽然两段代码的目的相同,但是具体的实现手段差别很大。其中命令式强调怎么做,使用的是 for 循环来遍历,而声明式强调做什么,用到了 double算子。
函数式编程之组合性:吃饭是一个方法、睡觉是一个方法… 这些方法可以组合成人的基本行为的一个方法,这就是组合的思想;
分离关注点:
大多数系统的设计做得不够好,问题常常出现在分解这步就没做好。常见的分解问题就是分解的粒度太大,把各种维度混淆在一起。在设计中,将一个模块的不同维度分开,有一个专门的说法,叫分离关注点。
分离关注点之所以重要,有两方面原因。一方面,不同的关注点混在一起会带来一系列的问题,正如前面提到的各种问题;另一方面,当分解得足够细小,你就会发现不同模块的共性,才有机会把同样的信息聚合在一起。这会为软件设计的后续过程,也就是组合,做好准备。
高阶函数
function hello() {
console.log('hello');
}
function sleep() {
console.log('sleep');
}
function doAction(fn) {
console.log('first do something');
fn();
}
doAction(hello);
doAction(sleep);
// 这样就将 first do something 就行了一个抽离
高阶函数和高阶组件本质上是一样的,只是高阶组件会返回一个DOM;
高阶函数与函数装饰器:
所谓高阶函数,是指输入参数是函数,或者返回值是函数的函数。
如果输入参数和返回值都是函数,这样的高阶函数又叫做函数装饰器(FunctionDecorators)。当一个高阶函数是用来修饰函数本身的,它就是函数装饰器。也就是说,它是在原始函数上增加了某些带有辅助功能的函数。
例如,在组件库进行大版本升级中,在未来最新的版本中我们想要废弃掉某些 API,由于很多业务中使用了老版本的库,不可能一次升级完,因此我们需要做一个平缓过渡。具体来说就是在当前这个版本中,先不取消这些旧的 API,而是给它们增加一个提示信息,告诉调用它们的用户,这些 API 将会在下一次升级中被废弃。如果我们手工修改要废弃的 API 代码,这会是一件非常繁琐的事情。而且,我们很容易遗漏或者弄错些什么,从而产生不可预料的 Bug。
所以,一个比较聪明的办法是,我们实现一个通用的函数装饰器。
然后,在模块导出 API 的时候,对需要废弃的方法统一应用这个装饰器。
这样,我们就利用函数装饰器,无侵入地修改了模块的 API,将要废弃的模块用deprecate 包装之后再输出,就实现了我们想要的效果。这里,我们实现的 deprecate 就是一个纯函数,它的维护和使用都非常简单。
再例如:
function hello() {
console.log('hello');
}
function helloWrapper(fn) {
return function () {
console.log('before hellor');
fn();
console.log('after hello');
}
}
hello = helloWrapper(hello);
hello()
总结:
- 高阶函数的作用:对公共部分进行一个抽离;
- 函数装饰器(如果输入参数和返回值都是函数,这样的高阶函数又叫做函数装饰器)的作用:对原有的功能进行装饰,但又不改变原有的功能。