博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
前端开发者进阶之函数反柯里化unCurrying
阅读量:6712 次
发布时间:2019-06-25

本文共 2443 字,大约阅读时间需要 8 分钟。

函数柯里化,是固定部分参数,返回一个接受剩余参数的函数,也称为部分计算函数,目的是为了缩小适用范围,创建一个针对性更强的函数。

那么反柯里化函数,从字面讲,意义和用法跟函数柯里化相比正好相反,扩大适用范围,创建一个应用范围更广的函数。使本来只有特定对象才适用的方法,扩展到更多的对象。

看一下通用函数:

Function.prototype.currying = function() {    var that = this;    return function() {        return Function.prototype.call.apply(that, arguments);    }}

短小精悍,科学上讲,浓缩的都是精品,但越精品的往往越难以理解。分解一下:

1 为Function原型添加unCurrying方法,这样所有的function都可以被借用;

2 返回一个借用其它方法的函数,这是目的;

3 借用call方法实现,但call方法参数传入呢?借用apply,至此完毕。

回头看看,好像也不难!

还有其它的实现方式:

Function.prototype.unCurrying = function () {    var f = this;    return function () {        var a = arguments;        return f.apply(a[0], [].slice.call(a, 1));    };};
Function.prototype.unCurrying = function () {    return this.call.bind(this);};

 原理都相同,最终是把this.method转化成 method(this,arg1,arg2....)以实现方法借用和this的泛化。

鸭式辩型:如果一个对象可以像鸭子一样走路,游泳,并且嘎嘎叫,就认为这个对象是鸭子,哪怕它并不是从鸭子对象继承过来的。

在javascript里面,很多函数都不做对象的类型检测,而是只关心这些对象能做什么。

Array构造器和String构造器的prototype上的方法就被特意设计成了鸭子类型。这些方法不对this的数据类型做任何校验。这也就是为什么arguments能冒充array调用push方法.
看下v8引擎里面Array.prototype.push的代码:
function ArrayPush() {    var n = TO_UINT32(this.length);    var m = %_ArgumentsLength();    for (var i = 0; i < m; i++) {        this[i + n] = %_Arguments(i); //属性拷贝        this.length = n + m; //修正length        return this.length;    }}

这就给对象冒充创造了条件,也就我们讨论的函数柯反里化unCurrying。反柯里化其实反映的是一种思想,扩大方法的适用范围!

看下面例了,让一个普通对象具备push方法:

var push = Array.prototype.push.unCurrying(),obj = {};push(obj, 'first', 'two');console.log(obj);/*obj {    0 : "first",    1 : "two"}*/

obj被push了两个元素:first 和two,同时还具备了一个length属性,其实我们创建了一类数组对象。

 再看一个例子:

var toUpperCase = String.prototype.toUpperCase.unCurrying();console.log(toUpperCase('avd')); // AVDfunction AryUpper(ary) {    return ary.map(toUpperCase);}console.log(AryUpper(['a', 'b', 'c'])); // ["A", "B", "C"]

只是方法都可以借用。包括call方法。

var call = Function.prototype.call.unCurrying();function $(id) {    return this.getElementById(id);}var demo = call($, document, 'demo');console.log(demo);

这似乎看起来相对于前两个例子,比较难理解,其实一句话就可以解释:document借用了$方法,并替换了其中的this。

在函数柯里化例子中bind的例子中,柯里化的目的是为了固定可变参数this。而反柯里化,把原来拥有方法的this泛化了,泛化到所有对象都可以借用,也就是替代当前拥有方法的this。

这里,希望不要混淆,这里的this并不是指上例中的this,上例中的this只是因为借用的方法是call。

更有趣的是,unCurrying本身也是方法,它是否可以被借用呢?答案是肯定的。这就是js的奇妙之处,反柯里化的奇妙之处。

看下面:

var unCurrying = Function.prototype.unCurrying.unCurrying();var map = unCurrying(Array.prototype.map);var sq = map([1, 2, 3],function(n) {    return n * n;});console.log(sq); // [1,4,9]

无论是柯里化还是反柯里化,其实反应的都是一种设计思想。这一节先到这里。

 

转载地址:http://vmxlo.baihongyu.com/

你可能感兴趣的文章
mysql问题
查看>>
为何要领域驱动设计
查看>>
ios GCD ---- (1)
查看>>
Pi编译安装PHP/Nginx并安装完整LEMP环境
查看>>
HTTPS 也不安全?被发现新漏洞会暴露你的数据
查看>>
x86 和 ARM 谁能主宰服务器市场?Linux 之父和 Redis 之父有分歧了
查看>>
dva.js学习梳理集
查看>>
ECS运维神器重装上阵,云助手亮相控制台
查看>>
Nacos 发布 0.9.0 版本,为 GA 作准备
查看>>
ECS控制台实例列表支持自动续费状态过滤
查看>>
运维利器 RunDeck v3.0.15 发布, 服务器自动化操作
查看>>
后端架构师技术图谱
查看>>
快速掌握:大型分布式系统中的缓存架构
查看>>
redis系列:分布式锁
查看>>
ES6(Proxy 和 Reflect)
查看>>
spring+springMVC+mybatis的整合 part1
查看>>
[Spark]Spark Streaming 指南四 输入DStreams和Receivers
查看>>
众安在线2018半年报:亏损6.668亿元,综合成本率高达124.0%
查看>>
java之 ------------[LeetCode] House Robber 打家劫舍||
查看>>
Android Recyclerview 实现画廊功能
查看>>