用bind方法保持this上下文

最近自学JavaScript,学到bind方法这块儿有些地方不太明白,自己就查了些资料,结合自己的理解写了这篇文章以备后面回顾用。。。其实应该还是搬砖为主吧。

什么是this对象

先来说说什么是this对象吧,每个函数在调用的时候都会自动获取两个特殊变量:this和arguments对象。this值具体是指哪个对象是和该函数的执行环境相关的。如果是作为对象的方法,那么this就是对象实例本身;如果是一个全局函数,那么this就是window对象。用一句话来概括,this就是调用这个方法的对象。

保持this上下文

有时候,我们需要保持this的上下文,也就是在一个执行环境中想要访问到另一个执行环境的this值。在什么时候需要这么做呢?比如说将一个对象的方法赋值给了一个全局变量,然后在全局变量中调用这个方法,那么this值就不再是原来的对象而是window对象了,然而可能我们仍需要在全局环境中按照对象的方法来调用。又比如说一个方法中包含了闭包,闭包是无法访问到其外部函数的this对象的,因为this对象是在调用方法的时候自动生成,内部函数在搜索这两个变量的时候只会搜索到其自身的活动对象,而不会沿着作用域链往外搜索,所以闭包访问不到外部函数的this值。如果要想访问,就应该想办法把this值传递下去。
通常可以通过这样的方式保持this上下文:在外部函数中将this缓存到一个变量中,通常变量名称使用self, _this 或者 context,那么闭包就可以通过这个可访问的变量来获取外部函数的this值,this上下文得以保持。比如下面的代码:

var myObj = {

    specialFunction: function () {},
    getAsyncData: function (cb) {
        cb();
    },

    render: function () {
        var that = this;
        this.getAsyncData(function () {
            that.specialFunction();
        });
    }
};
myObj.render();

这里有一个对象myObj,它有一个render实例方法,在这个方法内部又调用了它的另一个实例方法getAsyncData,而这个方法有一个新的函数作为参数,这个函数相当于是一个闭包,是不能获取到外部函数中的this值的,为了在这个闭包中也能访问实例方法,需要获取到外部环境的this值,这里把this(this为调用render方法的对象,即实例对象myObj)缓存到了变量that中。

此外还可通过bind方法,这就是本文所要讲述的重点。

bind方法

bind方法生成了一个新的函数,称为绑定函数,传入bind方法的第一个参数作为这个绑定函数的this对象,传入bind的第二个参数连同后面调用绑定函数时传入的参数按照先后顺序(传入bind的在前)构成绑定函数的参数。
现在我们把上面的例子修改一下:

render: function () {
    this.getAsyncData(function () {

        this.specialFunction();

    }.bind(this));

}

.bind()创建了一个函数,当这个函数在被调用的时候,它的 this 关键词会被设置成被传入的值(这里指调用bind()时传入的参数)
再看一个bind的使用例子:

var foo = {
    x: 3
} 
var bar = function(){
    console.log(this.x);
} 
bar(); 
// undefined

var boundFunc = bar.bind(foo);

boundFunc(); 
// 3

将bar方法和foo对象绑定后,bar中的this对象被替换为了foo,并生成了一个新的函数boundFunc,因此在全局环境中调用boundFunc时,也可以访问到foo对象的属性。
还可以了解一下Function.prototype.bind()内部是什么样的:

Function.prototype.bind = function (scope) {
    var fn = this;//this是调用bind方法的对象(别的方法对象)
    return function () {
        return fn.apply(scope);//把fn环境中的this替换为scope
    };
}

可看出,bind方法返回了一个新的函数,这个方法返回了原方法(调用bind的方法)通过apply修改作用域(传入的参数scope)后的执行结果。如果调用这个新函数则会立即执行fn.apply(scope),并返回执行后的结果。

fn.bind()

与call、apply的区别

call、apply是修改函数的作用域,并且立即执行,而bind是返回了一个新的函数,不是立即执行,即call and apply call a function while bind creates a function。bind在回调函数中常用到。

参考资料:
理解 JavaScript 中的 Function.prototype.bind
js中bind、call、apply函数的用法
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

你可能感兴趣的:(JavaScript)