js反柯里化

来源:互联网 发布:毛妹伤害数据 编辑:程序博客网 时间:2024/05/22 01:49

反柯里化主要是借用别人的函数,比如类数组没有push函数,但是可以借用push函数,[].push()调用的时候,push里面的this值是[],但是arguments.push()是不行的,因为arguments没有这个方法,那怎么办呢,反柯里化就是要修改里面的this值,所谓的this泛化,让this编程其他对象,从而达到借用的目的。以下是三个反科里化函数
文章内容借鉴于http://www.cnblogs.com/pigtail/p/3450852.html,稍微做了些修改而已。

反柯里化其实就是x.call(obj,1,2,3)的进化版,因为反柯里化的本质就是在我们想调用的函数里使用任意的this值。
Function.prototype.uncurring=uncurring
function uncurring() {
    var self = this;
    return function() {
        return  self.apply(arguments[0],[].slice.call(argumens,1))
    }
}

function uncurring() {

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

}


function uncurring() {
    
        return Function.prototype.call.bind(this)
   }

var push=Aarray.prototype.push.uncurring();

var a={}

push(a,1,2,3)//Object {0: 1, 1: 2, 2: 3, length: 3}

这时候a成为了push函数里的this值。

下面具体讲一下这三个函数的工作原理,其实都是一样的。反柯里化应用中,有几个知识点事比较重要的,

1.首先是call函数的大致实现原理,当我们执行x.call(obj,1,2,3)的时候,到底是做了什么?call的源代码大概是这样的:

function call(){

this(参数1,参数2,...参数n)//并且执行this函数的时候this代表的函数里面的this是call函数的第一个参数。

}

所以x.call(obj,1,2,3)的时候,相当于x(1,2,3)//x里面的this值等于obj。

2.还有一个比较重要的知识点是apply函数,当我们执行x.apply(obj,[1,2,3])的时候,最后执行的是this(1,2,3),apply函数会把他第二个参数(是一个数组),拆开一个个地赋值给调用函数的形参。而不是整个数组赋值给调用的函数。

我们用某一个函数调用uncurring函数的时候,首先要做的是利用闭包保存好该函数,因为后面要调用。我们执行var push=Aarry.prototype.push.uncurring()的时候,这时候push等于function(){ return Function.prototypr.call.apply(self,arguments)},当我们执行push的时候,执行的其实是Function.prototype.call.apply(self,arguments),这句话到底做了什么呢?根据apply的原理,这句代码的本质是Function.prototype.call(arguments[0],.....arguments[n])//call函数里面的this是self的值,也就是push。那么Function.prototype.call(........)到底又执行了什么呢?根据call的原理,我们知道这句代码的本质是this(参数1,参数2......)//this值是arguments[0],这里的重点是正常来说call里面的this应该是Function.prototype,但是因为刚才执行apply那句代码的时候,改变了this的值,所以这时候执行的其实是self的值,也就是push的值,所以最后执行的其实是push(arguments[1],arguments[2]....)//this是arguments[0],也就是obj。

chrome下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;
    }
}

所以最后会在obj上增加一系列的属性。反柯里化后返回的函数,执行该函数时,第一个参数就是最后执行的那个借用函数里使用的this值。


文章里还提到了一下这个应用,就是对call进行反柯里化。下面来解析一下代码。

var call = Function.prototype.call.unCurrying();

/*返回的是function(){

return Function.prototype.call.apply(self,arguments)//self的值是call

}*/
function $(id) {
    return this.getElementById(id);
}
var demo = call($, document, 'demo');

/*

执行这句代码其实就是执行Function.prototype.call.apply(Function.prototype.call,arguments),

其实就是执行Function.prototype.call($,document,"demo")//call里面的this是apply的第一个函数Function.prototype.call,

其实执行的就是this(document,"demo")//this是call函数,并且这个call函数里的this是$,

其实执行的就是$("demo")//$函数里面的this是document,

其实执行的就是document.getElementById("demo")

*/
console.log(demo);


文章还提到的一个是对uncurring函数就行uncurring化。

var unCurrying = Function.prototype.unCurrying.unCurrying();

/*

返回的是function(){

return Function.protoype.call.apply(self,arguments)//self是unCurring这个函数

}

*/
var map = unCurrying(Array.prototype.map);

/*

执行这个代码其实就是执行Function.prototype.call.apply(unCurring,arguments)

其实就是执行,Function.prototype.call(arguments[0])//this值是unCurring

其实就是执行unCurring()//this值是arguments[0],也就是Array.prototype.map

这个和前面的有点差别就是,前面的调用形式都是x.unCurring(),而这个的调用形式是unCurring(),调用unCurring最重要的是知道里面的this,所以这里的this值由call压进来,是Array.prototype.map函数。所以执行unCurring()时,返回的是function(){

Function.prototype.call.apply(self,arguments)//self的值是Array.prototype.map

},所以这时候就退化到了前面例子的情况。


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

function uncurring() {
    var self = this;
    return function() {
        return  self.apply(arguments[0],[].slice.call(argumens,1))
    }
}
0 0