改变this指向apply()、call()、bind()三种方法
我们都知道在JavaScript中apply()、call()、**bind()**的作用都是用来改变this指向的,那么为什么要改变this指向呢?一起看看下面的例子
var name="小明"; let obj={ name:"小红", say:function () { console.log(this.name); } }; obj.say(); //输出的结果是:小红,this指向obj对象 setTimeout(obj.say,0); //输出的结果是:小明,this指向window对象
可以观察到,正常情况下 say 方法中的 this 是指向调用它的 obj 对象的,而定时器 setTimeout 中的 say 方法中的 this 是指向window对象的(在浏览器中),这是因为 say 方法在定时器中是作为回调函数来执行的,因此回到主栈执行时是在全局执行上下文的环境中执行的,但我们需要的是 say 方法中 this 指向obj对象,因此我们需要修改 this 的指向。
如果一个标准函数,也就是非箭头函数,作为某个对象的方法被调用时,这个this指向的就是函数的调用者(某个对象)
箭头函数是一种特殊情况,this指向的是定义这个箭头函数的创造者,一般是window
那么要改变普通函数的this指向应该怎么做呢?其实在JavaScript中提供了三种方法可以改变this指向,分别是apply()、call()、bind(),下面来解释一下这三种方法
apply()
apply()方法:apply接收两个参数,第一个参数是this的指向,第二个参数是函数接收的参数,以数组的形式传入,且当第一个参数为null、undefined的时候,默认指向window(在浏览器中),使用apply方法改变this指向后原函数会立即执行,且此方法只是临时改变thi指向一次。
//示例 var name="martin"; var obj={ name:"lucy", say:function(year,place){ console.log(this.name+" is "+year+" born from "+place); } }; var say=obj.say; setTimeout(function(){ say.apply(obj,["1996","China"]) } ,0); //lucy is 1996 born from China,this改变指向了obj say("1996","China") //martin is 1996 born from China,this指向window,说明apply只是临时改变一次this指向
- 当第一个参数为null或者underfind时,默认指向window,我们来做一个求数组中的最大值案例
var arr=[1,10,5,8,3]; console.log(Math.max.apply(null, arr)); //输出:10
其中Math.max函数的参数是以参数列表形式传入,如:Math.max(1,10,5,8,3)的形式传入的,因此我们没法直接把数组当做参数,但是apply方法可以将数组参数转换成列表参数传入,从而直接求数组的最大值。
call()
**call()**方法:call方法的第一个参数也是this的指向,后面传入的是一个参数列表(注意和apply传参的区别)。当一个参数为null或undefined的时候,表示指向window(在浏览器中),和apply一样,call也只是临时改变一次this指向,并立即执行。
var arr=[1,10,5,8,3]; console.log(Math.max.call(null,arr[0],arr[1],arr[2],arr[3],arr[4])); //10 //采纳以参数列表的形式传入,而apply以参数数组的形式传入。
bind()
bind()方法:bind方法和call很相似,第一个参数也是this指向,后面传入的也是一个参数列表(但是这个参数列表可以分多次传入,call则必须一次性传入所有参数),但是它改变this指向后不会立即执行,而是返回一个永久改变this指向的函数。
function fun() { console.log(this); // 原来的函数this指向的是 Window } fun(); function fun(a, b) { console.log(this); // this指向了输入的 字符串bind console.log(a + b); } //使用bind() 方法改变this指向,此时第一个参数是 字符串bind,那么就会指向字符串bind let c = fun.bind('bind', 2, 3); c(); // 返回新的方法,需要重新调用 // 也可以使用下面两种方法进行调用 // fun.bind('bind', 2, 3)(); // fun.bind('bind')(2, 3);
apply,call,bind三者的区别
- 三者都可以改变函数的this对象指向。
- 三者第一个参数都是this要指向的对象,如果如果没有这个参数或参数为undefined或null,则默认指向全局window。
- 三者都可以传参,但是apply是数组,而call是参数列表,且apply和call是一次性传入参数,而bind可以分为多次传入。
- bind 是返回绑定this之后的函数,便于稍后调用;apply 、call 则是立即执行 。