探索call、apply、bind以及它们的区别

参考:【优雅代码】深入浅出 妙用Javascript中apply、call、bind

我查询了许多关于call、apply、bind的文章,大部分说的都比较官网,什么改变this指向之类的,本人非官方人,对官方内容看不懂,但是我对call、apply、bind有个比较粗陋的理解吧,call、apply、bind的第一个参数借用别人的方法,可能你看到我这句总结有点懵,没关系,请继续往下阅读,保证你能看懂

解释“call、apply、bind的第一个参数借用别人的方法”

先来个栗子吧

// 定义一个父亲
father = {
    // 定义个穿鞋动作
    wearShoes: function () {
        return '我在穿我的' + this.shoes + '鞋'
    }
}
// 定义一个儿子
son = {
    // 儿子有双NIKE鞋
    shoes: 'NIKE'
}

从上面的定义看,儿子有一双NIKE鞋,由于儿子年龄太小了,没有能力穿鞋,而爸爸会穿鞋,那么现在儿子想穿鞋,只能让爸爸帮忙穿鞋,粗陋的理解就是儿子借用爸爸的穿鞋方法来将自己的鞋穿到自己的脚上,写来我们来实现儿子这个想法

father = {
    // 定义个穿鞋动作
    wearShoes: function () {
        return '我在穿我的' + this.shoes + '鞋'
    }
}
// 定义一个儿子
son = {
    // 儿子有双NIKE鞋
    shoes: 'NIKE'
}
father.wearShoes.call(son) // 我在穿我的NIKE鞋
father.wearShoes.apply(son) // 我在穿我的NIKE鞋
father.wearShoes.bind(son)() // 我在穿我的NIKE鞋

我们可以看出son想拥有father.wearShoes方法,需要借助call、apply、bind。另外要注意的是在father调用wearShoes时函数内使用的this指的就是father,但是son通过call、apply、bind调用wearShoes时,this指的不是father了而是son了,这点一定要注意,这也正是官方说的修改了this的指向。
另外最后三行你看出有什么区别了吗?
call和apply用法一样,但是bind后面有添加了(),貌似是bind执行完之后返回的是函数,然后再通过()调用一下

bind 详解

MDN的解释是:bind()方法会创建一个新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以创建它时传入 bind()方法的第一个参数作为 this,传入 bind() 方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数。

直接来看看具体如何使用,在常见的单体模式中,通常我们会使用 _this , that , self 等保存 this ,这样我们可以在改变了上下文之后继续引用到它。 像这样:

var foo = {
    bar : 1,
    eventBind: function(){
        var _this = this;
        $('.someClass').on('click',function(event) {
            /* Act on the event */
            console.log(_this.bar);     //1
        });
    }
}

由于 Javascript 特有的机制,上下文环境在 eventBind:function(){ } 过渡到 $('.someClass').on('click',function(event) { }) 发生了改变,上述使用变量保存 this 这些方式都是有用的,也没有什么问题。当然使用 bind() 可以更加优雅的解决这个问题:

var foo = {
    bar : 1,
    eventBind: function(){
        $('.someClass').on('click',function(event) {
            /* Act on the event */
            console.log(this.bar);      //1
        }.bind(this));
    }
}

在上述代码里,bind() 创建了一个函数,当这个click事件绑定在被调用的时候,它的 this 关键词会被设置成被传入的值(这里指调用bind()时传入的参数)。因此,这里我们传入想要的上下文 this(其实就是 foo ),到 bind() 函数中。然后,当回调函数被执行的时候, this 便指向 foo 对象。再来一个简单的栗子:

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

这里我们创建了一个新的函数 func,当使用 bind() 创建一个绑定函数之后,它被执行的时候,它的 this 会被设置成 foo , 而不是像我们调用 bar() 时的全局作用域。

有个有趣的问题,如果连续 bind() 两次,亦或者是连续 bind() 三次那么输出的值是什么呢?像这样:

var bar = function(){
    console.log(this.x);
}
var foo = {
    x:3
}
var sed = {
    x:4
}
var func = bar.bind(foo).bind(sed);
func(); //?
 
var fiv = {
    x:5
}
var func = bar.bind(foo).bind(sed).bind(fiv);
func(); //?

答案是,两次都仍将输出 3 ,而非期待中的 4 和 5 。原因是,在Javascript中,多次 bind() 是无效的。更深层次的原因, bind() 的实现,相当于使用函数在内部包了一个 call / apply ,第二次 bind() 相当于再包住第一次 bind() ,故第二次以后的 bind 是无法生效的。

你可能感兴趣的:(探索call、apply、bind以及它们的区别)