在JavaScript中,当我们调用对象的某个方法时,其实不用去关心该对象原本是否被设计为拥有这个方法,这是动态类型语言的特点。可以通过反柯里化(uncurrying)函数实现,让一个对象去借用一个原本不属于他的方法。

通常让对象去借用一个原本不属于它的方法,可以用call和apply实现,如下

var obj1 = {
name:'sven'
}
var obj2 = {
getName:function(){
return this.name
}
}
console.log(obj2.getName.call(obj1))//sven

更常见的场景之一是让类数组对象去借用Array.prototype的方法;

(function(){
Array.prototype.push.call(arguments,4)
console.log(arguments);//[1, 2, 3, 4]
})(1,2,3)

扩展:为什么类数组对象能够借用数组的方法呢?不妨理解下V8的引擎源码,就以Array.prototype.push为例:

function ArrayPush() {
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.push");
var array = TO_OBJECT(this);
var n = TO_LENGTH_OR_UINT32(array.length);
var m = %_ArgumentsLength();
.......
for (var i = 0; i < m; i++) {
array[i+n] = %_Arguments(i);
}
var new_length = n + m;
array.length = new_length;
return new_length;
}

通过这段代码大致可以看出,Array.prototype.push实际上是一个属性复制的过程,把参数按照下标依次添加到被push的对象上面,顺便修改了这个对象的length属性,这个对象到底是数组还是类数组并不重要。从源码可以看出,只要对象本身可以存取属性,且length属性可读写,就可以借用Array原型的push方法。

这样一来,方法中用到this的地方,就不在局限原本的对象,而是加以泛化并得到更广的适用性。那么有没有办法把泛化this的过程提取出来呢?那么反柯里化(uncurrying)就是解决这个问题的。反科里化(uncurrying)的话题来自JavaScript之父Brendan Eich在2011年发表的一篇文章,以下代码是实现方式之一:

Function.prototype.uncurrying = function() {
var self = this;
return function() {
var obj = Array.prototype.shift.call(arguments);
return self.apply(obj, arguments);
};
};

然后就可以定义一个push函数,更加简洁和明了的实现了一个不在局限于数组的push方法。如下:

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)
};
}
看似实现很简单,但理解就有点费力,再次做下阐释:
按照上边的push反柯里化函数Array.prototype.push.uncurrying()分析:
1.self = Array.prototype.push函数;
2.apply中的arguments = [目标数组,参数1,参数2]//实例中就等同于[[1,2,3],4]
对函数原型call方法执行apply方法作用相当于
Function.prototype.call.apply(Array.prototype.push,[[1,2,3],4])
再参考下边call和apply类源码实现进行分步理解
Function.prototype.apply= function(context,array) {
  // this=Function.prototype.call; context=Array.prototype.push; array=[[1,2,3],4]
context.fn = this;
  //Array.prototype.push.fn = Function.prototype.call.bind(Array.prototype.push) 第一步
var args = [];
for(var i = 0, len =array.length; i < len; i++) {
args.push('arguments[' + i + ']');
}
eval('context.fn(' + args +')');
  // Array.prototype.push.fn([1,2,3],4)=== Function.prototype.call.bind(Array.prototype.push)([1,2,3],4) 第二步
  
delete context.fn;
}
Function.prototype.call = function(context) {//[1,2,3],4

  //由第二步bind可知this为Array.prototype.push context=[1,2,3] arguments=[[1,2,4],4]
context.fn = this;
  //[1,2,3].fn=Array.prototype.push.bind([1,2,3]) 第三步
var args = [];
  //0为上下文,所以此处参数遍历应从1开始
for(var i = 1, len = arguments.length; i < len; i++) {
args.push('arguments[' + i + ']');
}
eval('context.fn(' + args +')');
  //[1,2,3].fn(4) === Array.prototype.push.bind([1,2,3])(4) 第四步
delete context.fn;
}
Array.prototype.push.bind([1,2,3])(4)===Array.prototype.push.call([1,2,3],4)

 

 https://92node.com/article/js-uncurrying.html

参考书籍:javascript设计模式与开发实践

javascript之反柯里化(uncurrying)的更多相关文章

  1. javascript之反柯里化uncurrying

    使用方法: // 使用 var push=Array.prototype.push.uncurrying(); var obj={ "length": 1, "0&quo ...

  2. 前端开发者进阶之函数反柯里化unCurrying

    函数柯里化,是固定部分参数,返回一个接受剩余参数的函数,也称为部分计算函数,目的是为了缩小适用范围,创建一个针对性更强的函数. 那么反柯里化函数,从字面讲,意义和用法跟函数柯里化相比正好相反,扩大适用 ...

  3. JS中的反柯里化( uncurrying)

    反柯里化 相反,反柯里化的作用在与扩大函数的适用性,使本来作为特定对象所拥有的功能的函数可以被任意对象所用.即把如下给定的函数签名, obj.func(arg1, arg2) 转化成一个函数形式,签名 ...

  4. JS 函数的柯里化与反柯里化

    ===================================== 函数的柯里化与反柯里化 ===================================== [这是一篇比较久之前的总 ...

  5. 浅析 JavaScript 中的 函数 uncurrying 反柯里化

    柯里化 柯里化又称部分求值,其含义是给函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具体的函数接受剩下的参数,这中间可嵌套多层这样的接受部分参数函数,直至返回最后结果. 因此柯里化的过程是 ...

  6. JavaScript 反柯里化

    浅析 JavaScript 中的 函数 uncurrying 反柯里化 柯里化 柯里化又称部分求值,其含义是给函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具体的函数接受剩下的参数,这中间 ...

  7. 简单粗暴详细讲解javascript实现函数柯里化与反柯里化

    函数柯里化(黑人问号脸)???Currying(黑人问号脸)???妥妥的中式翻译既视感:下面来一起看看究竟什么是函数柯里化: 维基百科的解释是:把接收多个参数的函数变换成接收一个单一参数(最初函数的第 ...

  8. JavaScript中的反柯里化

    转载自:https://www.cnblogs.com/zztt/p/4152147.html 柯里化 柯里化又称部分求值,其含义是给函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具体的函 ...

  9. JavaScript中的函数柯里化与反柯里化

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

随机推荐

  1. 混合开发中ios兼容问题

    1. z-index无效,设置层级,发现再ios中无效,后来发现是设置了 -webkit-overflow-scrolling:touch 设置这个属性之后.层级设置失效 2.@keyup事件的问题, ...

  2. vue视频: 自定义指令 && 拖拽 && 自定义键盘信息

    v-textv-forv-html 指令: 扩展html语法 自定义指令:1. 自定义属性指令: Vue.directive(指令名称,function(参数){ this.el -> 原生DO ...

  3. 【php】---mysql---基本操作及使用---【巷子】

    1.数据库简介 (1).什么是数据库?     一个文件  一个文件夹  一个u盘   一个硬盘......都叫做数据库    存放数据的仓库   (2).常见的数据库?     mySql  sql ...

  4. ios8铃声

    ios8铃声最新铃声 MP3版本 链接: http://pan.baidu.com/s/1bnGS8Uz 密码: 94g7 m4r版本 链接: http://pan.baidu.com/s/1pJyT ...

  5. 修改hosts搭建本地站点

    想要搭建本地站点.例如想要将www.nbb.com映射到本地服务器,而不是网络的.需要修改hosts文件 1 打开hosts所在目录  C:\Windows\System32\drivers\etc ...

  6. YOGA Tablet 2 1371f 触屏失效,无声卡,蓝牙键盘都无法使用的解决办法

    安装驱动! 下载地址 http://www.lenovocare.com.cn/Handler/Download.ashx?fileid=1234 安装后电源管理,声卡,触摸屏即可使用! 蓝牙键盘连接 ...

  7. MySQL server has gone away With statement: INSERT INTO `students`......

    mysql出现ERROR : (2006, 'MySQL server has gone away') 的问题意思就是指client和MySQL server之间的链接断开了. 首选分析给出可能出现的 ...

  8. Web前台学习总结

    前台的技术有很多种,流行的框架也是枚不胜举,在这里我们只讨论html,css,js这些基本的技术,相信大家如果掌握了这些最基本的技术,其他的技术也就会使用了. 下面是一个案例的形式来讲解上述的技术. ...

  9. And Design:拓荒笔记——Form表单

    And Design:拓荒笔记——Form表单 Form.create(options) Form.create()可以对包含Form表单的组件进行改造升级,会返回一个新的react组件. 经 For ...

  10. 1:3访问 servlet API 的两种方式(request,session等内置对象)

    1:解耦方式 2:耦合方式: ========================================== ========================================== ...