JavaScript中apply, call和bind的区别
首先要知道,JavaScript中apply,call 和 bind的作用基本都是一样的,就是用来改变函数执行时的上下文,或者说改变函数的this对象指向
在详细了解它们的区别之前,我们先来看一个例子
var name = "mike"; const obj = { name: "luke", say:function() { console.log(this.name); } }; obj.say(); //输出luke setTimeout(obj.say,0) // 输出mike
这里,会不会觉得很奇怪,第一个obj.say()输出luke应该很好理解,因为这个时候this指向的就是obj对象,所以this.name, 肯定就是obj里面的name => luke
第二个setTimeout(obj.say,0) 为什么输出的mike呢,这里会感觉很奇怪 => setTimeout()这是个定时器,里面的第一个参数是个回调函数,也就是说obj.say是作为回调函数来执行的, 执行回调函数,需要回到主栈上执行,也就是在全局执行上下文的环境中执行,这个时候的this指向的是windows, 所以,这个时候调用obj.say => 输出 this.name => this指的是全局的windows对象,所以返回的是mike
那么问题来了,现在我的需求就是,在定时器中调用回调函数obj.say,但是我要的是输出luke,而不是mike, 我应该怎么办,有没有方法呢 => 首先我们想,我们要达到的目的,就是在setTimeout(obj.say,0)中,改变这里面的obj.say方法里面的this的指向,现在它指向的是windows全局对象,我们要把它指向obj, 那有没有方法做到这点呢 =》 这就是我们今天要讲的这3个东西,改变函数的this对象指向 或者说 改变函数执行时的上下文
先说结果 =》 这里可以这么改 setTimeout(obj.say.bind(obj),0); 通过使用.bind(obj) 来把this绑定obj对象,此时,输出的就是luke
call,apply,bind都是Function.prototype下的方法,目标都是改变函数的上下文, 最终的返回值是你调用方法的返回值, 如果该方法没有返回值, 那么就是返回undefined
call 和 apply基本是一样的,作用也完全一样,唯一不同就是接受参数的方式不一样(apply的第二个参数是一个数组或者arguments对象, callc从第二个参数开始,后面是参数列表). 你可以把call看做是apply的语法糖。 call 和 apply一样,都是立即执行调用.
这点和bind不一样,bind是返回绑定this之后的函数,一个新函数
语法:
apply([thisObj[,argArray]])
call([thisObj[,arg1[, arg2[, [,.argN]]]]])
上面 thisObj的取值有以下4种情况:
1. 不传, 或者null, undefined, 函数中的this指向window对象
2. 传递另一个函数的函数名, 函数中的this指向这个函数的引用
3. 传递字符串,数值或布尔类型等基础类型, 函数中的this指向其对应的包装对象 String, Number, Boolean
4. 传递一个对象,函数中的this指向这个对象
总结:
apply,call 和 bind都可以改变函数的this指向,都是可以用来改变函数执行时的上下文
它们的第一个参数都是this要指向的对象,如果没有这个参数,或者参数为undefined,或者为null, 则默认指向全局的window
三者都可以传参,但是apply是数组, call是参数列表,而且apply和call是一次性传入参数, 而bind可以分多次传入
bind是返回绑定this之后的函数,一个新函数. 而apply, call则是立即执行调用
三者的使用场景:
如果不需要关心具体有多少参数被传入函数,选用apply()
如果确定函数可接收多少个参数,并且想一目了然地表达形参和实参的对应关系,用call()
如果我们想返回一个新函数以供后面调用,不需要立即得到函数返回结果,使用bind()