ECMAScript 2017 中的函数组合:更好的函数调用控制和代码复用
在计算机编程领域,函数式编程是一种模式。函数式编程的主要特点是函数可以作为值进行传递,函数的输出仅取决于输入。在这个模式中,我们往往会将一些小型的函数组合在一起,以实现更高级别的函数。这种高级别函数对于代码的权衡、解耦和复用非常有帮助。在 JavaScript 中,函数组合也是一种流行的编程模式,而 ECMAScript 2017 带来了一些关于函数组合的新特性。
函数组合有什么好处?
函数组合的最大好处是代码复用。通过组合多个小型函数,我们可以创建一个高级别的函数,这个函数可以在我们的代码库中任何需要这些小型函数的地方调用。
如果我们将函数的输入和输出描述为以下关系:
input1 -> output1 -> input2 -> output2 -> input3 -> output3 -> ...
那么,函数组合的本质就是将这些函数的输入和输出关系连接在一起,就像建立一个管道一样:
input1 -> output1 -> input2 -> output2 -> input3 -> output3 -> ... | | | func1 func2 func3 | | | V V V --- --- ---
这种方式非常有利于提高代码复用性,因为我们可以使用相同的小型函数来组合各种大型函数。另外,这种方式也非常有利于测试,因为我们可以单独测试每个小型函数,并检查它们是否正确组合在一起。
函数组合的常规用法
在 ECMAScript 2017 中,我们可以通过一个名为 compose()
的新函数来组合多个函数。compose()
的思路非常简单:给定一组函数 f1, f2, f3 ... fn 和一个值 x,将这些函数与 x 组合在一起,使其表达式等于:
fn(...(f3(f2(f1(x)))))
我们可以将 compose()
想象成一个管道,它会将给定的值从一个函数传递到另一个函数,直到最后一个函数返回最终结果:
const f1 = x => x + 1; const f2 = x => x * 2; const f3 = x => x - 3; const composedFn = compose(f1, f2, f3); console.log(composedFn(10)); // 17
在这个例子中,我们定义了三个函数 f1
、f2
和 f3
,然后将它们传递给 compose()
函数。这样,我们就创建了一个新的函数 composedFn
,并将其赋值为 compose(f1, f2, f3)
的结果。当我们执行 composedFn(10)
时,这个函数会将 10 作为输入值,将其带入到 f1
中,然后将 f1
函数的输出值带入到 f2
中,再将 f2
函数的输出值带入到 f3
中,最终输出 17。
compose()
函数还有一个非常棒的特性:它可以接收任意数量的函数作为参数,并将它们组合在一起。这样,我们就可以创建任意数量的函数组合。
从右向左执行的组合函数: pipe()
compose()
函数的主要问题是它按照常规的从左向右顺序执行函数,这种顺序可能并不符合我们的需求。例如,假设我们有两个函数 f1
和 f2
,我们希望在第一个执行 f2
,然后才执行 f1
,compose()
并不能满足我们的要求。
为了解决这个问题,ECMAScript 2017 提供了另一个函数:pipe()
。pipe()
函数和 compose()
函数非常相似,但是它按照从右向左的顺序执行函数:
const f1 = x => x + 1; const f2 = x => x * 2; const f3 = x => x - 3; const pipedFn = pipe(f3, f2, f1); console.log(pipedFn(10)); // 17
在这个例子中,我们将 f3
、f2
和 f1
函数传递给 pipe()
函数,它会按照从右向左的顺序执行这些函数。这样我们就创建了一个名为 pipedFn
的新函数,当我们调用 pipedFn(10)
时,会首先将 10 带入到 f1
中,接着将 f1
函数的输出值带入到 f2
中,将 f2
函数的输出值带入到 f3
中,最终输出 17。
值得注意的是,pipe()
和 compose()
的返回值都是新函数,这是为了避免在组合过程中破坏原始函数,同时也为了保持组合的灵活性。
避免空参数的组合函数:pipeK()
和 composeK()
默认情况下,compose()
和 pipe()
函数在遇到空参数时,会抛出错误。例如:
const f1 = x => x + 1; const f2 = x => x * 2; const f3 = x => x - 3; const composedFn = compose(f1, f2, null, f3); // Uncaught TypeError: Cannot read property 'apply' of null
在这个例子中,我们故意传递了一个空函数到 compose()
函数中,并且期望组合函数仍然能够正常运行,但是 compose()
函数并不具备容错能力。
为了解决这个问题,ECMAScript 2017 新增了两个带有容错机制的组合函数:composeK()
和 pipeK()
。这两个函数会跳过任何输入参数为空的函数。
const f1 = x => x + 1; const f2 = x => x * 2; const f3 = x => x - 3; const composedFn = composeK(f1, f2, null, f3); console.log(composedFn(10)); // 17
在这个例子中,我们将 null
传递给 composeK()
函数,但它不会抛出任何错误,而是跳过这个参数并继续执行组合函数的后续步骤。
总结
函数组合是一种非常强大的编程模式,可以提高代码的复用性和可维护性。在 ECMAScript 2017 中,我们可以使用 compose()
和 pipe()
函数来创建函数组合,而 composeK()
和 pipeK()
函数则提供了输入容错的功能。尽管这些函数的规则非常简单,但它们的表现出色,可以大大提高 JavaScript 代码的工作效率和可读性。
参考示例代码
-- -------------------- ---- ------- ----- ------- - ---------- -- ---------------- -- -- --------- -- --------------- ----- ---- - ---------- -- --------------------- -- -- --------- -- --------------- ----- -------- - ---------- -- ------------- --- -- -- - -- ---- - - -- ---- - - - --------- -- ------------- - - -- ----- ----- - ---------- -- ------------------ --- -- -- - -- ---- - - -- ---- - - - --------- -- ------------- - - -- ----- -- - - -- - - -- ----- -- - - -- - - -- ----- -- - - -- - - -- ----- ---------- - ----------- --- ---- ----- ------- - -------- --- ---- ----- ----------- - ------------ --- ----- ---- ----- -------- - --------- --- ----- ---- ---------------------------- -- -- ------------------------- -- -- ----------------------------- -- -- -------------------------- -- --
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/64f8c1e3f6b2d6eab3098d02