javascript之反柯里化(uncurrying)
在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)的更多相关文章
- javascript之反柯里化uncurrying
使用方法: // 使用 var push=Array.prototype.push.uncurrying(); var obj={ "length": 1, "0&quo ...
- 前端开发者进阶之函数反柯里化unCurrying
函数柯里化,是固定部分参数,返回一个接受剩余参数的函数,也称为部分计算函数,目的是为了缩小适用范围,创建一个针对性更强的函数. 那么反柯里化函数,从字面讲,意义和用法跟函数柯里化相比正好相反,扩大适用 ...
- JS中的反柯里化( uncurrying)
反柯里化 相反,反柯里化的作用在与扩大函数的适用性,使本来作为特定对象所拥有的功能的函数可以被任意对象所用.即把如下给定的函数签名, obj.func(arg1, arg2) 转化成一个函数形式,签名 ...
- JS 函数的柯里化与反柯里化
===================================== 函数的柯里化与反柯里化 ===================================== [这是一篇比较久之前的总 ...
- 浅析 JavaScript 中的 函数 uncurrying 反柯里化
柯里化 柯里化又称部分求值,其含义是给函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具体的函数接受剩下的参数,这中间可嵌套多层这样的接受部分参数函数,直至返回最后结果. 因此柯里化的过程是 ...
- JavaScript 反柯里化
浅析 JavaScript 中的 函数 uncurrying 反柯里化 柯里化 柯里化又称部分求值,其含义是给函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具体的函数接受剩下的参数,这中间 ...
- 简单粗暴详细讲解javascript实现函数柯里化与反柯里化
函数柯里化(黑人问号脸)???Currying(黑人问号脸)???妥妥的中式翻译既视感:下面来一起看看究竟什么是函数柯里化: 维基百科的解释是:把接收多个参数的函数变换成接收一个单一参数(最初函数的第 ...
- JavaScript中的反柯里化
转载自:https://www.cnblogs.com/zztt/p/4152147.html 柯里化 柯里化又称部分求值,其含义是给函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具体的函 ...
- JavaScript中的函数柯里化与反柯里化
一.柯里化定义 在计算机科学中,柯里化是把 接受多个参数的函数 变换成 接受一个单一参数(最初函数的第一个参数)的函数 并且返回 接受余下参数且返回结果的新函数的技术 高阶函数 高阶函数是实现柯里化的 ...
随机推荐
- Eclipse中将Java项目转换成Web项目的方法(转)
前言: 用Eclipse开发项目的时候,把一个Web项目导入到Eclipse里会变成了一个java工程,将无法在Tomcat中进行部署运行. 方法: 1.找到.project文件,找到里面的<n ...
- Android中的Apk的加固(加壳)原理解析和实现(转)
一.前言 今天又到周末了,憋了好久又要出博客了,今天来介绍一下Android中的如何对Apk进行加固的原理.现阶段.我们知道Android中的反编译工作越来越让人操作熟练,我们辛苦的开发出一个apk, ...
- 基于ArcGIS for Server的服务部署分析 分类: ArcGIS for server 云计算 2015-07-26 21:28 11人阅读 评论(0) 收藏
谨以此纪念去年在学海争锋上的演讲. ---------------------------------------------------- 基于ArcGIS for Server的服务部署分析 -- ...
- android data recovery and nc
目录下会出现mmcblk0.raw文件,文件大小等于手机内部存储空间的大小,该文件正是手机内部存储空间的镜像文件. 第七步,打开一款传统的数据恢复工具,由于raw文件是linux文件系统格式,因此需要 ...
- mysql 数据操作 单表查询
单表查询的语法 distinct 去重 SELECT 字段1,字段2... FROM 表名 库.表名 WHERE 条件 过滤 符合条件的 GROUP BY field 分组条件 HAVING 筛选 过 ...
- 整合最优雅SSM框架:SpringMVC + Spring + MyBatis 基础
在写代码之前我们先了解一下这三个框架分别是干什么的? 相信大以前也看过不少这些概念,我这就用大白话来讲,如果之前有了解过可以跳过这一大段,直接看代码! SpringMVC:它用于web层,相当于con ...
- POJ2115:C Looooops(一元线性同余方程)
题目: http://poj.org/problem?id=2115 要求: 会求最优解,会求这d个解,即(x+(i-1)*b/d)modm;(看最后那个博客的链接地址) 前两天用二元一次线性方程解过 ...
- Selenium之IE浏览器的启动问题及解决
前面有篇文章说到启动IE浏览器时,会出现以下错误提示: 浏览器启动之后,页面不会自动输入代码设置的地址,如下图展示 查看报错语句,发现原来是浏览器比例调的不正确,修改浏览器比例为100%即可解决该问题
- javascript-复制
cefCopy:function(str){ var t=this; if(!str || str=="暂无激活码") { $.notice("暂无激活码", ...
- 5.6 Components -- Handling User Interaction with Actions
1. 组件允许你定义可以在整个应用程序中重用的控件.如果它们够通用,它们也可以在被共享给其他人并且在许多应用程序中被使用. 2. 为了使一个可重用的控件有用,然而,你首先需要你的应用程序的用户和它交互 ...