javascript之反柯里化(uncurrying)

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

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

更常见的场景之一是让类数组对象去借用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)
  };
}

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

原文地址:https://www.cnblogs.com/dupd/p/8449711.html

时间: 2024-12-10 23:32:13

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

javascript之反柯里化uncurrying

使用方法: 1 // 使用 2 var push=Array.prototype.push.uncurrying(); 3 var obj={ 4 "length": 1, 5 "0": 1 6 } 7 push(obj,2); 8 console.log(obj); // { 0=1, 1=2, length=2} 9 10 function fn(name){ 11 console.log(this.name); //test 12 console.log(ar

JavaScript 反柯里化

浅析 JavaScript 中的 函数 uncurrying 反柯里化 柯里化 柯里化又称部分求值,其含义是给函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具体的函数接受剩下的参数,这中间可嵌套多层这样的接受部分参数函数,直至返回最后结果.因此柯里化的过程是逐步传参,逐步缩小函数的适用范围,逐步求解的过程.请见我的另一篇博客· 浅析 JavaScript 中的 函数 currying 柯里化 反柯里化 相反,反柯里化的作用在与扩大函数的适用性,使本来作为特定对象所拥有的功能的函数可以

柯里化与反柯里化

柯里化 什么是柯里化 柯里化(英语:Currying),是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术. 柯里化的基础 上面的代码其实是一个高阶函数(high-order function), 高阶函数是指操作函数的函数,它接收一个或者多个函数作为参数,并返回一个新函数.此外,还依赖与闭包的特性,来保存中间过程中输入的参数.即: 函数可以作为参数传递 函数能够作为函数的返回值 闭包 通用实现 var currying

js之柯里化与反柯里化

先给大家介绍什么是柯里化与反柯里化 百度翻译: 在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术.这个技术由 Christopher Strachey 以逻辑学家 Haskell Curry 命名的,尽管它是 Moses Schnfinkel 和 Gottlob Frege 发明的. 柯里化 柯里化又称部分求值,其含义是给函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具

JS的防抖,节流,柯里化和反柯里化

今天我们来搞一搞节流,防抖,柯里化和反柯里化吧,是不是一看这词就觉得哎哟wc,有点高大上啊.事实上,我们可以在不经意间用过他们但是你却不知道他们叫什么,没关系,相信看了今天的文章你会有一些收获的 节流 首先我们来搞一下节流,啥叫节流,就是将高频率触发事件变成低频率触发事件,举个简单的例子,但我们用window.onscroll滚动事件的时候你会发现滚轮滑动一次可能会触发好多次事件, 代码: window.onscroll = function(){ console.log("触发")

js反柯里化个人理解以及操作

学过js的都知道原型是js的灵魂,我刚接触原型的时候觉得还挺绕的,然后看了一系列的解释然后自己理了一下思路,总算是清晰了,今天我弄了一下柯里化和反柯里化,对反柯里化结合原型链有了一定的认识,一下是我所总结的. 反柯里化,个人解释就是通过添加对象或者函数的原型的方法,让原本使用范围具有局限性的一段代码能够适用范围更广,例如,数组的reduce,map,foreach这些函数都只能通过数组对象使用,如果字符串要使用其方法,必须通过call,bind,apply的方式去修改函数的调用主体,但是我们完全

JavaScript中的柯里化

今天在博客园首页看到一篇好文章 [译]理解JavaScript中的柯里化 加上最近工作中的一些感悟,算是对函数式编程语言(scala, python, javascrtpt)中的闭包,偏函数.柯里化有了更进一步的认识. 之前学Scala被绕的云里雾里的各种名词,现在也开始慢慢理解了. 上面那篇文章写的很好,这里就只说一下自己实际用到的一个例子. 现在需要对流速进行转换,流速的单位有 bps.Kbps.Mbps.Gbps.Tbps,从一个单位转换到另一个单位需要除N次1000. 可能需要有从bps

javascript中利用柯里化函数实现bind方法

柯理化函数思想:一个js预先处理的思想:利用函数执行可以形成一个不销毁的作用域的原理,把需要预先处理的内容都储存在这个不销毁的作用域中,并且返回一个小函数,以后我们执行的都是小函数,在小函数中把之前预先存储的值进行相关的操作处理即可: 柯里化函数主要起到预处理的作用: bind方法的作用:把传递进来的callback回调方法中的this预先处理为上下文context; /** * bind方法实现原理1 * @param callback [Function] 回调函数 * @param con

浅谈JavaScript中的柯里化函数

首先,不可避免的要引经据典啦,什么是柯里化函数呢(from baidu): 在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术.这个技术由 Christopher Strachey 以逻辑学家 Haskell Curry 命名的,尽管它是 Moses Schnfinkel 和 Gottlob Frege 发明的. 用于创建已经设置好了一个或多个参数的函数 与函数绑定相似,他们之间的区