函数绑定与函数柯里化

一、函数绑定(bind)

什么是函数绑定?

  • 函数绑定需要创建一个函数,可以在特定的this环境中以指定参数调用另一个函数。
  • 常与回调函数及事件处理程序一起使用,以便在将函数作为变量传递的同时保留代码执行环境。
var handler = {
    message: 'Event handled',
    handleClick: function(event) {
        console.log(this.message);
    }
};
var btn = document.getElementById('my-btn');
EventUtil.addHandler(btn,'click',handler.handleClick);

上述例子中,创建了一个handler的对象。handler.handleClick()方法被分配为一个DOM按钮的事件处理程序。当按下该按钮时,就调用该函数,输出打印数据,按我们看到的讲,会打印输出’Event handled’,然而事实却是输出undefined。这是因为没有保存handler.handleClick()的环境,所以this指向了DOM按钮并非handler。
我们可以使用闭包来修正环境问题。

EventUtil.addHandler(btn,'click',function(event) {
    handler.handleClick(event);   //恍然大悟,原来平时使用的事件监听就用到了闭包。
});

这个解决方案在onclick事件处理程序内使用了一个闭包直接调用handler.handleClick()。当然,这是鉴于这段代码的解决方案。在其他特定条件下创建多个闭包可能会使代码变得难以理解。因此js库实现了一个可以将函数绑定到指定环境的函数。这个函数就是bind()函数。

bind()

一个简单的bind()函数接受一个函数和一个环境,并返回一个在给定环境中调用给定函数的函数,并且将所有参数原封不动传递过去。

function bind(fn,context) {
    return function() {
        return fn.apply(context,arguments);
    }
}

这个函数看上去简单,但是其功能是非常强大的。在bind()函数中创建了一个闭包,闭包使用apply()调用传入的函数,并给apply()传递context对象和参数。需要注意的是,这里使用的arguments对象是内部函数的,而非bind()的。当调用返回的函数时,它会在给定环境中执行被传入的函数并给出所有参数。

EventUtil.addHandler(btn,'click',bind(handler.handleClick,handler));

二、函数柯里化

与函数绑定紧密相关的是函数柯里化。

  • 函数柯里化用于创建已经设置好了一个或者多个参数的函数
  • 基本方法和函数绑定一致:使用一个闭包返回一个函数。
  • 区别在于,当函数被调用时,返回的函数还需要设置一些需要传入的参数。
function add(num1,num2) {
    return nums1 + num2;
}
function curriedAdd(num2) {
    return add(5,num2);
}
console.log(add(2,3))   // 5
console.log(curriedAdd(3))   // 8

这面这俩个函数,后者本质上是在任何情况下第一个参数都为5的add()版本。但其实curriedAdd()并非柯里化的函数,但是很好的展示了其概念。
柯里化函数通常由一下步骤动态创建:调用另一个函数并为它传入要柯里化的函数和参数。下面为创建柯里化函数的通用方式。

function curry(fn) {
    var args = Array.prototype.slice.call(arguments,1); //获取除第一个参数外的所有参数;第一个参数是要进行柯里化的函数;
    return function() {
        var innerArgs = Array.prototype.slice.call(arguments);  // innerArgs用来存放所有传入的参数(内部函数的参数)
        var finalArgs = args.concat(innerArgs);    // 有了存放来自外部函数和内部函数的参数数组后,组合为finalArgs
        return fn.apply(null,finalArgs); //使用apply()将结果传递给该函数。需要注意的是这个函数没有考虑到执行环境,所以调用apply()时的第一个参数为null。
    };
}

function add(num1,num2) {
    return nums1 + num2;
}
var curriedAdd = curry(add,5);
console.log(curriedAdd(add,3))   // 8

利用柯里化实现复杂的bind()

function curry(fn,context) {
    var args = Array.prototype.slice.call(arguments,2); 
    return function() {
        var innerArgs = Array.prototype.slice.call(arguments);  
        var finalArgs = args.concat(innerArgs);    
        return fn.apply(context,finalArgs); 
    };
}

柯里化实现add(1)(2,3)(5)

function add() {
    var args = Array.prototype.slice.call(arguments); 
    return function() {
        var innerArgs = Array.prototype.slice.call(arguments);  
        if(arguments.length == 0) {
            var sum = 0;
            for(var i in args) {
                sum += args[i];
            }
            return sum;
        } else {
           var finalArgs = args.concat(innerArgs);    
           return add.apply(this, finalArgs)
        } 
    }
};
console.log(add(1)(2,3)(5)()); // 11
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值