函数柯里化是把接受多个参数的函数转变成接受一个单一参数 (最初函数的第一个参数), 并且返回接受余下的参数而且返回结果的新函数的技术
柯里化其实本身是固定一个可以预期的参数, 并返回一个特定的函数, 处理批特定的需求这增加了函数的适用性, 但同时也降低了函数的适用范围
通用定义
- function currying(fn){
- var slice = Array.prototype.slice;
- _args = slice.call(arguments,1);
- return function(){
- var _inargs = slice.call(arguments);
- return fn.apply(null,_args.concat(_inargs))
- }
- }
提高适用性
通用函数解决兼容性问题, 但是同时也会带来使用的不便利性, 不同的应用场景往往要传递很多参数, 已达到解决特定的目的. 有时候应用中, 会对同一个规则进行反复使用, 这样就造成了代码的重复性.
- function square(i){
- return i * i;
- }
- function dubble(i){
- return i *= 2;
- }
- function map(handeler,list){
- return list.map(handeler)
- }
- // 数组的每一项平方
- map(square, [1, 2, 3, 4, 5]);
- map(square, [6, 7, 8, 9, 10]);
- map(square, [10, 20, 30, 40, 50]);
- // 数组的每一项加倍
- map(dubble, [1, 2, 3, 4, 5]);
- map(dubble, [6, 7, 8, 9, 10]);
- map(dubble, [10, 20, 30, 40, 50]);
例子中, 创建了一个 map 通用函数, 用于适应不同的应用场景显然, 通用性不用怀疑同时, 例子中重复传入了相同的处理函数: square 和 dubble
应用中这种可能会更多当然, 通用性的增强必然带来适用性的减弱但是, 我们依然可以在中间找到一种平衡
看下面, 我们利用柯里化改造一下:
- function square(i) {
- return i * i;
- }
- function dubble(i) {
- return i *= 2;
- }
- function map(handeler, list) {
- return list.map(handeler);
- }
- var mapSQ = currying(map, square);
- mapSQ([1, 2, 3, 4, 5]);
- mapSQ([6, 7, 8, 9, 10]);
- mapSQ([10, 20, 30, 40, 50]);
- var mapDB = currying(map, dubble);
- mapDB([1, 2, 3, 4, 5]);
- mapDB([6, 7, 8, 9, 10]);
- mapDB([10, 20, 30, 40, 50]);
我们缩小了函数的适用范围, 但同时提高函数的适性
由此, 可知柯里化不仅仅是提高了代码的合理性, 更重的它突出一种思想 --- 降低适用范围, 提高适用性
下面再看一个例子, 一个应用范围更广泛更熟悉的例子:
- function Ajax() {
- this.xhr = new XMLHttpRequest();
- }
- Ajax.prototype.open = function(type, url, data, callback) {
- this.onload = function() {
- callback(this.xhr.responseText, this.xhr.status, this.xhr);
- }
- this.xhr.open(type, url, data.async);
- this.xhr.send(data.paras);
- }
- 'get post'.split(' ').forEach(function(mt) {
- Ajax.prototype[mt] = currying(Ajax.prototype.open, mt);
- });
- var xhr = new Ajax();
- xhr.get('/articles/list.php', {},
- function(datas) {
- // done(datas)
- });
- var xhr1 = new Ajax();
- xhr1.post('/articles/add.php', {},
- function(datas) {
- // done(datas)
- });
2 延迟执行
柯里化的另一个应用场景是延迟执行不断的柯里化, 累积传入的参数, 最后执行
看下面:
- var add = function() {
- var _this = this,
- _args = arguments
- return function() {
- if (!arguments.length) {
- var sum = 0;
- for (var i = 0,
- c; c = _args[i++];) sum += c
- return sum
- } else {
- Array.prototype.push.apply(_args, arguments) return arguments.callee
- }
- }
- }
- add(1)(2)(3)(4)(); //10
通用的写法:
- var curry = function(fn) {
- var _args = []
- return function cb() {
- if (arguments.length == 0) {
- return fn.apply(this, _args)
- }
- Array.prototype.push.apply(_args, arguments);
- return cb;
- }
- }
上面累加的例子, 可以实验一下怎么写?
3 固定易变因素
柯里化特性决定了它这应用场景提前把易变因素, 传参固定下来, 生成一个更明确的应用函数最典型的代表应用, 是 bind 函数用以固定 this 这个易变对象
- Function.prototype.bind = function(context) {
- var _this = this,
- _args = Array.prototype.slice.call(arguments, 1);
- return function() {
- return _this.apply(context, _args.concat(Array.prototype.slice.call(arguments)))
- }
- }
来源: https://juejin.im/post/5a96481d6fb9a0633f0e4cc1