了解 JavaScript 函数式编程 - 代码组合的优势
栏目: JavaScript · 发布时间: 5年前
内容简介:组合函数看起来像是在养植物。你就是养殖员,选择两个有特点又被你喜欢的植物,让它们嫁接(结合)一下,产下一个崭新的品种(函数)。组合的用法如下:就像这样我们把两个函数组合之后返回一个新的函数。
组合函数看起来像是在养植物。你就是养殖员,选择两个有特点又被你喜欢的植物,让它们嫁接(结合)一下,产下一个崭新的品种(函数)。组合的用法如下:
var compose = function(f,g) { return function(x) { return f(g(x)); }; }; 复制代码
f
和 g
都是函数, x
是在它们之间通过“管道”传输的值。这里得注意一下 compose 函数是组合代码思想中最重要的一环,下面:point_down:会经常用到。大家可以提前 mark 一下
var toUpperCase = function(x) { return x.toUpperCase(); }; var exclaim = function(x) { return x + '!'; }; var shout = compose(exclaim, toUpperCase); shout("send in the clowns"); //=> "SEND IN THE CLOWNS!" 复制代码
就像这样我们把两个函数组合之后返回一个新的函数。
对比组合函数
思考一下: 组合的函数和一个完整流程的函数有什么区别
var shout = function(x){ return exclaim(toUpperCase(x)); }; 复制代码
可以看到组合的函数就像乐高玩具一样可以自由的组合成其他的可用的完整的模型乐高建模(完整功能的函数),但是一个像上方一样完整功能,不可拆卸对的函数的。它就像一个已经完成的手办。
- 可以拆解,组合成其他的乐高模型
- 不可拆解,出厂的时候已经设计好了。
了解组合代码
让代码从右向左运行,而不是由内而外运行,我觉得可以称之为“左派”(消音~)。我们来看一个顺序很重要的例子:
var head = function(x) { return x[0]; }; var reverse = reduce(function(acc, x){ return [x].concat(acc); }, []); var last = compose(head, reverse); last(['jumpkick', 'roundhouse', 'uppercut']); //=> 'uppercut' 复制代码
上面就是一个反转数组的操作,这里我们看到一个组合函数的执行顺利,我们可以主动的操作函数进行从左到右的方式,但是从右向左的执行顺序更加符合数学上的含义。基本的高中数学知识
// 结合律(associativity) var associative = compose(f, compose(g, h)) == compose(compose(f, g), h); // true compose(toUpperCase, compose(head, reverse)); // 或者 compose(compose(toUpperCase, head), reverse); 复制代码
结合律的好处
结合律的好处是任何一个函数分组都可以被拆解开来,然后再以他们自己的组合打包在一起,组合成新的函数。curry 就是我们的 工具 包。
- 下面用到了上面 compose 、head、reverse 函数
var loudLastUpper = compose(exclaim, toUpperCase, head, reverse); // 或 var last = compose(head, reverse); var loudLastUpper = compose(exclaim, toUpperCase, last); // 或 var last = compose(head, reverse); var angry = compose(exclaim, toUpperCase); var loudLastUpper = compose(angry, last); // 更多变种... 复制代码
pointfree 空数据模式
pointfree 模式是,no data 模式的意思。这里有一句来自《Love Story》70 年代的电影的台词--“Love means never having to say you're sorry”。
- 我们的 pointfree 模式就是“Pointfree style means never to say your data”。
- 下面我们就可以使用柯里化、组合代码中实现以下 pointfree style
// 非 pointfree,因为提到了数据:word var snakeCase = function (word) { return word.toLowerCase().replace(/\s+/ig, '_'); }; // pointfree var snakeCase = compose(replace(/\s+/ig, '_'), toLowerCase); // 不明白为什么看看最上面的 compose 函数,然后在 控制台试试 snakeCase 函数 snakeCase('Hello World') // hello_world 复制代码
在 pointfree 版本中,不需要 word 参数就能构造函数;而在非 pointfree 的版本中,必须要有 word 才能进行一切操作。
pointfree 模式能够帮助我们减少不必要的命名,让代码保持简洁和通用。
组合代码的常见问题 debug~
组合的一个常见错误是,在没有局部调用之前,就组合类似 map 这样接受两个参数的函数。
// 下面部分函数来自于上面的 #### 结合律的好处 // 错误做法:我们传给了 `angry` 一个数组,根本不知道最后传给 `map` 的是什么东西。 var latin = compose(map, angry, reverse); latin(["frog", "eyes"]); // error // 正确做法:每个函数都接受一个实际参数。 var latin = compose(map(angry), reverse); latin(["frog", "eyes"]); // ["EYES!", "FROG!"]) 复制代码
使用 trace(追踪) 来跟踪你的函数
var trace = curry(function(tag, x){ console.log(tag, x); return x; }); var dasherize = compose(join('-'), toLower, split(' '), replace(/\s{2,}/ig, ' ')); dasherize('The world is a vampire'); // TypeError: Cannot read property 'apply' of undefined -------------- // 看到报错了,来 trace 一下 var dasherize = compose(join('-'), toLower, trace("after split"), split(' '), replace(/\s{2,}/ig, ' ')); // after split [ 'The', 'world', 'is', 'a', 'vampire' ] ------------- // tolower 的参数徐亚的是一个数组,所以这里我们 fix 一下我们的代码 var dasherize = compose(join('-'), map(toLower), split(' '), replace(/\s{2,}/ig, ' ')); dasherize('The world is a vampire'); // 'the-world-is-a-vampire' 复制代码
trace 的好处就是可以直接定位到函数调用的地方,允许我们在某个特定的点去观察我们的函数数据
总结
我们可以认为哦组合是高于其他所有原则的设计原则,这是因为组合让我们的代码简单而富有可读性。另外范畴学将在应用架构、模拟副作用和保证正确性方面扮演重要角色。
衍生知识点:一些命名方式
name | demo |
---|---|
CamelCase(小驼峰) | personId |
PascalCase(帕斯卡/大驼峰) | PersonId |
SnakeCase(下横线) | person_id |
KebabCase(中横线) | person-id |
参考
以上所述就是小编给大家介绍的《了解 JavaScript 函数式编程 - 代码组合的优势》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。