详解JavaScript中的不完全函数

作者:admin     字体:[增加 减小]    类型:原创
在JavaScript中,不完全函数是一种函数变换技巧,即把一次完整的函数调用拆成多次函数调用,每次传入的实参都是完整实参的一部分,每个拆分开的函数叫做不完全函数,每次函数调用叫做不完全调用。

在JavaScript中,不完全函数是一种函数变换技巧,即把一次完整的函数调用拆成多次函数调用,每次传入的实参都是完整实参的一部分,每个拆分开的函数叫做不完全函数,每次函数调用叫做不完全调用,这种变换的特点是每次调用都返回一个函数,直到得到最终运行结果为止,举一个简单的例子,将对函数f(1,2,3,4,5)的调用修改为等价的f(1,2)(3,4)(5,6),后者包含三次调用,和每次调用相关的函数就是“不完全函数”。

在《postLink()98223》文章中bind()方法返回一个新函数,处理的就是不完全函数。但是传入bind()的实参都是放在传入原始函数的实参列表开始的位置,但是我们有时候期望将bind()的实参放在右侧。

//实现一个工具函数,将类数组(或对象)转换为真正的数组
//在后面的示例代码中用到了这个方法将arguments对象转换为真正的数组
function array(a,n){
    return Array.prototype.slice.call(a,n||0);
}

//这个函数的实参传递至左侧
function partialLeft(f){
    var args = arguments;   //保存外部的实参数组
    return function(){      //并返回这个函数
        var a = array(args,1);  //从第一个元素开始处理args
        a = a.concat(array(arguments)); //然后增加所有的内部实参
        return f.apply(this,a); //然后基于这个实参列表调用f()
    }
}

//这个函数的实参传递至右侧
function partialRight(f){
    var args = arguments;   //保存外部的实参数组
    return function(){      //并返回这个函数
        var a = array(arguments);   //从内部参数开始
        a = a.concat(array(args,1));    //从第一个元素开始处理args
        return f.apply(this,a); //然后基于这个实参列表调用f()
    }
}

//这个函数的实参传递至左侧
//如果参数为undefined,用后面的实参填充undefined
function partial(f){
    var args = arguments;   //保存外部实参数组
    return function(){
        var a = array(args,1);  //从外部args开始
        //遍历args,从内部实参填充undefined值
        for(var i=0,j=0;i<a.length;i++){
            if (a[i]===undefined) a[i] = arguments[j++];
        }
        //现在将剩下的内部实参都追加进去
        a = a.concat(array(arguments,j));
        return f.apply(this,a);
    };
}

//这个函数带有三个实参
var f = function(x,y,z){return x*(y-z);};

//注意这三个不完全调用之间的区别
console.log(partialLeft(f,2)(3,4)); //-2,绑定第一个实参:2*(3-4)
console.log(partialRight(f,2)(3,4));    //6,绑定第一个实参:3*(4-2)
console.log(partial(f,2)(3,4));     //-2,绑定第一个实参:2*(3-4)
console.log(partial(f,undefined,2)(3,4));   //-6,绑定第一个实参:3*(2-4)