前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >初识JavaScript柯理化

初识JavaScript柯理化

作者头像
FinGet
发布2019-06-28 14:39:40
2640
发布2019-06-28 14:39:40
举报
文章被收录于专栏:FinGet前端之路FinGet前端之路

什么是柯理化

在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。

把含有N个参数的函数转变成,N个只有一个参数的函数。

中心思想:降低通用性,提高适用性。

通用的设计比适用的设计复杂,因此更难使用。

特点:

  • 参数复用
  • 提前返回 (return)
  • 延迟执行

参数复用

例子

瑞士军刀,上面有小剪刀,但是这个小剪刀肯定没有一个单独的剪刀好用。

代码语言:javascript
复制
function square(i) {
  return i * i;
}
function dubble(i) {
  return i * 2;
}
function dobble(i) {
  return i * 1.9;
}
function map(handeler, list) {
  return list.map(handeler);
}
// 必须要传第一个参数,才能使用map函数
console.log(map(square, [1,2,3,4,5]));
console.log(map(square, [6,7,8,9,10]));
// 容易混淆
console.log(map(dubble, [1,2,3,4,5]));
console.log(map(dobble, [1,2,3,4,5]));
console.log(map(dubble, [6,7,8,9,10]));
代码语言:javascript
复制
// 提高适用性 语义清除,方便使用
// 假设存在一个curry方法
var mapSQ = curry(map, square);
mapSQ([1,2,3,4,5]);
mapSQ([6,7,8,9,10]);

var mapDQ = curry(map, dubble);
mapDQ([1,2,3,4,5]);
mapDQ([6,7,8,9,10]);
代码语言:javascript
复制
function ajax(type, url, data) {
  var xhr = new XMLHttpRequest();
  xhr.open(type, url, true);
  xhr.send();
}
ajax('POST', 'www.baidu.com', 'name=finget');
ajax('POST', 'www.baidu.com', 'name=bios');
ajax('POST', 'www.baidu.com', 'name=mario');

// 柯理化 减少参数
var ajaxCurry = curry(ajax);

// 用POST请求
var post = ajaxCurry('POST');
post('www.baidu.com','name=finget');

var postFromBaidu = post('www.baidu.com');
postToBaidu('name=finget');

// 以上代码类似与 $.ajax => $.post / $.get
  • 参数的多少跟函数体的复杂性成正比
  • 参数的多少跟函数的维护难度成正比
  • 参数的多少跟用户的使用难度成正比

成熟的框架jquery, lodash 一个方法基本不超过4个参数。大多数就是3个或者2个参数,方法体不超过40行

一个简单的柯理化函数
代码语言:javascript
复制
function add(a,b) {
  return a + b;
}

console.log(add(5,10)); // 15

const curryAdd = function (a) {
  return function(b) {
    return a + b;
  }
}

console.log(curryAdd(5)(10)); // 15
代码语言:javascript
复制
const add5 = curryAdd(5);
// 这里就类似与var post = ajaxCurry('POST');
console.log(add5(10)); // 15

延迟执行

代码语言:javascript
复制
var fishWeight = 0;
var addWeight = function(weight){
  fishWeight += weight;
}
addWeight(2.3);
addWeight(6.5);
addWeight(1.2);
addWeight(3);

console.log(fishWeight); // 13
代码语言:javascript
复制
var curryWeight = function(fn){
  var _fishWeight = [];
  return function(){
  // apply会执行函数
  // 传入参数时,先把他们存在数组中,当没有传参就执行计算
	if (arguments.length === 0) {
	  return fn.apply(null, _fishWeight);
	} else {
	  // [].slice.call(arguments) 复制一下我们的arguments然后将内容加到我们的_fishWeight中
	  _fishWeight = _fishWeight.concat([].slice.call(arguments));
	}
 }
}
var curryAddWeight = curryWeight(function(){
  var i = 0; len = arguments.length;
  for (i; i < len; i++) {
    fishWeight += arguments[i];
  }
})
代码语言:javascript
复制
curryAddWeight(2.3);
curryAddWeight(6.5);
curryAddWeight(1.2);
curryAddWeight(3);
// curryAddWeight(); 不加这句,console.log(fishWeight); // 0
console.log(fishWeight); // 0

柯理化后的函数是可以复用的 // 求平均值

代码语言:javascript
复制
var avgWeight = curryWeight(function(){
  var i = 0; len = arguments.length;
  for (i; i < len; i++) {
    fishWeight += arguments[i] / len;
  }
})
代码语言:javascript
复制
avgWeight(2.3);
avgWeight(6.5);
avgWeight(1.2);
avgWeight(3);
// avgWeight(); 不加这句,console.log(fishWeight); // 0
console.log(fishWeight); // 0

实现一个通用的一元curry函数

  • curry函数
代码语言:javascript
复制
function curry(fn, args) {
  var length = fn.length; // 方法参数个数 *注1
  args = args || [];
  return function(){
    var _args = args.slice(0), arg, i;
    for (i=0;i<arguments.length;i++){
	  arg = arguments[i];
	  _args.push(arg);
	}
	if (_args.length < length) {
	  return curry.call(this, fn, _args);
	} else {
	  return fn.apply(this, _args);
	}
  }
}

注1:var length = fn.length; // 方法参数个数 *注1 function add (a, b, c) { return a + b + c; } console.dir(add);

  • 使用curry函数

这个curry方法可以解决一元柯理化的场景,不是万能的

代码语言:javascript
复制
function add (a, b) {
 return a + b;
}
var curryAdd = curry(add);
var curryAdd5 = curry(add, [5]);
console.log(curryAdd(5)(10)); // 15
console.log(curryAdd5(10)); // 15
代码语言:javascript
复制
function add (a, b, c) {
  return a + b + c;
}
var curryAdd = curry(add);
var curryAdd5 = curry(add, [5]);
console.log(curryAdd(5)(10)(15)); // 30
console.log(curryAdd(5,10)(15)); // 30
console.log(curryAdd(5)(10,15)); // 30
console.log(curryAdd(5,10,15));	// 30
console.log(curryAdd5(10)(15));	// 30
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-02-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是柯理化
    • 特点:
    • 参数复用
      • 例子
        • 一个简单的柯理化函数
    • 延迟执行
    • 实现一个通用的一元curry函数
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档