手写简易版的curry

简介: 手写简易版的curry

手写简易版的curry


TL;DR

这是最终的结果

function curry(fn, ...args1) {
  if (args1.length >= fn.length) {
    return fn(...args1);
  }
  return function(...args2) {
    return curry(fn, ...args1, ...args2);
  };
}

正文

首先,我说下,不怎么常见的小知识,函数的长度。

函数有 length 的属性,而length 就是形参的个数。

// fn有a,b两个形参,
function fn(a, b) {}
// 那长度就是2,跟实参没关系~~
console.log(fn.length);

柯里化curry 就是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数。

大白话就是fn(a,b,c)进行 curry(fn) 之后,可以curriedFn(a)(b,c)

// 自己跟着步骤,一步步往下推导加思考,必须自己思考
// 先实现一个函数  add(1,2) => 3,这步要是卡住的话,嗯。。。。
function add(x, y) {
  return x + y;
}
// 再想想怎么实现 curriedAdd(1)(2) => 3,这步要是卡住的话,你可以去看看什么是高阶函数了
function curriedAdd(x) {
  return function(y) {
    return x + y;
  };
}
// 再想想 等价替换,x+y可以换成add么
function curriedAdd_v2(x) {
  return function(y) {
    return add(x, y);
  };
}
// 再想想,add要是三个参数,可以 curriedAdd_v2(1,2)(3),也就是上面的x,y可能不止一个参数
function curriedAdd_v3(...args1) {
  return function(...args2) {
    return add(...args1, ...args2);
  };
}
// 试着将add以参数的形式传进来
function curriedAdd_v4(fn, ...args1) {
  return function(...args2) {
    return fn(...args1, ...args2);
  };
}
// 将函数换个名字currying,毕竟脱离add了,这步就感觉离成功不远了!!!抽象到一定程度了!!!
function currying(fn, ...args1) {
  return function(...args2) {
    return fn(...args1, ...args2);
  };
}
// 目前的currying只能后面接两次括号 如 currying(add,1)(2,3)
// 试着升级下,后面接三个括号 currying(add,1)(2)(3)
function currying_v2(fn, ...args1) {
  return function(...args2) {
    return function(...args3) {
      fn(...args1, ...args2, ...args3);
    };
  };
}
// 再等价替换,第二个return的内容是不是跟currying很像
// 来努力努力换下
function currying_v3(fn, ...args1) {
  return function(...args2) {
    // return function(...args3){
    //     fn(...args1, ...args2,...args3);
    // }
    // 相当于
    // return currying(fn,...args1,...args2)
    // currying其实就是currying_v3
    return currying_v3(fn, ...args1, ...args2);
  };
}
// 这里说下,如果一开始参数齐的话就不用返回函数了,相当于我一开始就 curriedAdd(1,2,3)
// 为什么在这里说,理论上上面每个函数都需要加上这个判断,但这样的话核心功能看着就会没那么突出,所以放在这里。
// 没错,上面每个函数为了全乎都是需要加上这个判断滴~~~
// 所以这里加下这个条件,友情提示,用到函数长度了哟
function currying_v4(fn, ...args1) {
  if (args1.length >= fn.length) {
    return fn(...args1);
  }
  return function(...args2) {
    return currying_v4(fn, ...args1, ...args2);
  };
}
// currying_v4再换个名字curry,最后一步了,哇咔咔,写到这里面试也就过了
function curry(fn, ...args1) {
  if (args1.length >= fn.length) {
    return fn(...args1);
  }
  return function(...args2) {
    return curry(fn, ...args1, ...args2);
  };
}

uncurrying

此节直接引用《JavaScript设计模式与开发实践》。

用 call 和 apply可以把任意对象当作 this 传入某个方法,这样一来,方法中用到 this 的地方就不再局限于原来 规定的对象,而是加以泛化并得到更广的适用性。

那么有没有办法把泛化 this 的过程提取出来呢? uncurrying 就是用来解决这个问题的。以下代码是 uncurrying 的实现方式之一

Function.prototype.uncurrying = function() {
  var self = this;
  return function() {
      console.log(1,arguments)
    var obj = Array.prototype.shift.call(arguments);
      console.log(2,arguments)
      console.log(3,obj)
    return self.apply(obj, arguments);
  };
};
var push = Array.prototype.push.uncurrying();
let arr = [1, 2, 3];
push(arr, 4);
var push = Array.prototype.push.uncurrying();
(function() {
  push(arguments, 4);
  console.log(arguments); // 输出:[1, 2, 3, 4]
})(1, 2, 3);
// 另一种方式
Function.prototype.uncurrying = function() {
  var self = this;
  return function() {
    return Function.prototype.call.apply(self, arguments);
  };
};

参考资料

curry 的含义和理解

柯里化和反柯里化

目录
相关文章
|
6月前
|
XML Java 数据格式
手写spring框架——第一篇
手写spring框架——第一篇
42 0
|
2月前
|
XML 缓存 Java
手写Spring源码(简化版)
Spring包下的类、手写@ComponentScan注解、@Component注解、@Autowired注解、@Scope注解、手写BeanDefinition、BeanNameAware、InitializingBean、BeanPostProcessor 、手写AnnotationConfigApplicationContext
手写Spring源码(简化版)
01 # 手写 new 的原理
01 # 手写 new 的原理
43 0
|
6月前
|
SQL 设计模式 Java
干翻Mybatis源码系列之第十篇:Mybatis拦截器基本开发、基本使用和基本细节分析
干翻Mybatis源码系列之第十篇:Mybatis拦截器基本开发、基本使用和基本细节分析
|
6月前
|
SQL Java 数据库连接
解锁数据库操作新境界:轻松上手的MyBatis快速入门指南
解锁数据库操作新境界:轻松上手的MyBatis快速入门指南
59 0
|
SQL Java 数据库连接
[推荐] MyBatis框架初学笔记-为之后拾遗
[推荐] MyBatis框架初学笔记-为之后拾遗
57 0
|
设计模式 Java Spring
用300行代码手写1个Spring框架,麻雀虽小五脏俱全
为了解析方便,我们用application.properties来代替application.xml文件,具体配置内容如下:
46 0
|
缓存 前端开发 API
手写中实现并学习ahooks——useRequest
最近业务没有之前紧张了,也是消失了一段时间,也总结了一些之前业务上的问题。 和同事沟通也是发现普通的async + await + 封装api在复杂业务场景下针对于请求的业务逻辑比较多,也是推荐我去学习一波ahooks,由于问题起源于请求,因此作者也是直接从 useRequest 开始看起。
187 1
|
缓存 网络协议 应用服务中间件
手写Tomcat源码简易篇
手写Tomcat源码简易篇
|
SQL XML JavaScript
MyBatis的10种精妙用法,真是妙啊!
MyBatis的10种精妙用法,真是妙啊!