浅析 JavaScript 中的 Function.prototype.bind() 方法

Function.prototype.bind()方法

bind() 方法的主要作用就是将函数绑定至某个对象,bind() 方法会创建一个函数,函数体内this对象的值会被绑定到传入bind() 函数的值。

例如,在 f() 函数上调用 bind() 方法并传入参数 obj ,即 f.bind(obj) ,这将返回一个新函数, 新函数会把原始的函数 f() 当做 obj 的方法来调用,就像 obj.f() 似的,当然这时 f() 函数中的 this 对象指向的是 obj

简单使用情形一

var o={
    f: function () {
        var self=this;
        var fff=function() {
            console.log(self.value);  //此时 this 指向的是全局作用域 global/window,因此需要使用 self 指向对象o
        };
        fff();
    },
    value: "Hello World!"
};
o.f(); // Hello World! 

上例是我们常用了 保持 this 上下文的方法,把 this 赋值给了中间变量 self,这样在内部嵌套的函数中能够使用 self 访问到对象o,否则仍使用 this.value,内部嵌套函数的this此时指向的是全局作用域,最后的输出将会是 undefined,代码如下:

var o={
    f: function () {
        var self=this;
        var fff=function() {
            console.log(this.value); 
        };
        fff();
    },
    value: "Hello World!"
};
o.f(); // undefined

但是,如果我们使用 bind()函数,将fff函数的绑定在对象o中,即将fff()函数内部的 this 对象绑定为对象 o,那么可以遇见此时 this.value 是存在的。代码如下:

var o={
    f: function () {
        var self=this;
        var fff=function() {
            console.log(this.value); // bind(this) 中 this 指向的是o,这里也可直接写成 bind(o)
        }.bind(this);
        fff();
    },
    value: "Hello World!"
};
o.f(); // Hello World!

更普遍的使用情形

再看一个例子:

function f(y,z){
    return this.x+y+z;
}
var m=f.bind({x:1},2); 
console.log(m(3));  // 6

最后将输出 6

这是因为 bind()方法会把传入它的第一个实参绑定给f函数体内的 this,从第二个实参起,将依此传递给原始函数,因此 {x:1}传递给this ,2传递给形参ym(3) 调用时的3 传递给形参z

其实这个例子 f() 函数能够处理部分参数,分步计算 ( bind() 时处理了参数x,和参数y,调用 m(3)时处理了参数z )的过程其实是一个典型的Curry过程(Currying)。

bind()背后的简单原理

那么bind函数背后做了什么呢? 我们可以用以下代码来模拟:

Function.prototype.testBind = function (scope) {
    var fn = this;                                // this 指向的是调用testBind方法的一个函数
    return function () {
        return fn.apply(scope, arguments);
    }
};

下面是测试的例子:

var foo = {x: "Foo "};
var bar = function (str) {
    console.log(this.x+(arguments.length===0?'':str));
};

bar();                                   // undefined

var testBindBar = bar.testBind(foo);     // 绑定 foo
testBindBar("Bar!");                     // Foo Bar!

当调用 testBind() 后,我们创建了一个新的函数,通过调用 applythis 设置成 foo, OK,现在应该比较清晰了,但实际 bind() 的实现远比上面的复杂,如上面提到的 curry化过程等,上面只是主要原理便于学习理解 bind() 函数。

参考资料:
Javascript权威指南

posted @ 2014-11-26 03:23  Tong Zeng  阅读(10963)  评论(0编辑  收藏  举报