相信很多人在面试或者做面试题的时候都会碰到有关JavaScript中的apply,call以及bind的问题,所以在这里我为大家简单地介绍一下这三者之间的用法以及异同点。
首先是这三者之间的共同点,用一句话来概括就是:改变this的指向。
看到这里或许有人对于this还是有些不理解,那我就先花点时间讲解一下js中的this,如果已经充分理解this的可以略过这部分,直接往下看。
1.什么是this?
在学习this之前请记住一句话“this的最终指向的是那个调用它的对象”,下面我们通过几个例子来好好理解这句话的含义。
<script>
function init(){
var a = 1;
console.log(this.a); //结果是undefined
console.log("---------------");
console.log(this); //结果是window
}
init();
</script>
结果如下图:
上面那个函数中的console.log(this.a)执行的结果是undefined,从console.log(this)中可以看出来这个时候的init()函数中的this指向的是全局对象window,这是因为上面代码中的init();就相当于window.init();也就是说调用init函数中的this指针的最终对象是window而不是init函数,所以才会出现上面的结果。
<script>
var init = {
a : 1,
show: function () {
console.log(this.a);//结果为1
console.log("---------------");
console.log(this);//结果为init
}
}
init.show();
</script>
结果如下图:
解释一下上面的init为一个对象,而a和show都是对象init中的属性,a为init中的变量,show则为init中的函数,可以看到这次的结果的this.a指向的是对象init中的a,this则是指向了对象init,其实上面代码中的init.show();也可以相当于window.init.show();,只是要记住“this指向的是最终调用它的那个对象”,无论是init.show();还是window.init.show();最终调用show中的this指针都是init对象。
2.apply,call,bind
刚刚讲到了这三者的共同点是改变this的指向,具体是怎么做的我们通过几个例子来了解一下。
<script>
var init = {
a : 1,
show: function () {
console.log(this.a);
console.log(this);
}
}
var take = {
a: 2
}
init.show();
console.log('---------apply----------');
init.show.apply(take);
console.log('---------call----------');
init.show.call(take);
console.log('---------bind----------');
init.show.bind(take)();
</script>
结果如下图:
解释代码:可以看到对象take中没有定义方法show,这个时候为了代码的简洁性,防止重复代码,减少工作量,我们会选择调用init中的show方法,但是show方法使用了this指针并且指向的是init对象,这个时候apply,call,bind就发挥了它们的作用;从上面代码我们可以发现这三者的使用方式都是先调用另外一个对象的方法后跟上apply,call,bind,而括号中则是你改变this指针后要指向的对象,上文中则是take对象。
细心的你观看上面代码可能已经发现了这三者的一些区别,那就是bind后面多跟了一个括号,这是因为apply和call使用是立即执行函数,而bind则是返回一个函数,加上括号是让它自执行一次。
但是这不是这三者之间的最大区别,它们之间最大的区别在于如果调用的函数带参的时候传参的方式不一样,call方法是将参数一个一个传进去,而apply则是将参数先变成数组在以数组形式传进去,具体例子如下:
<script>
var init = {
age : 0,
show: function (name,sex) {
console.log(name+"年龄是"+this.age+",性别是"+sex);
}
}
var take = {
age: 20
}
console.log('---------apply----------');
init.show.apply(take,["lisa","女"]); //以数组形式传参
console.log('---------call----------');
init.show.call(take,"jack","男"); //一个一个进行传参
</script>
放上结果图:
至于bind与其他两者的区别就是刚才提到的使用bind你得到的结果是一个函数你可以在后面加上一个括号手动调用它。