前言:八股罢了,简单来说就是来改变this指向

基本使用

call()apply()bind() 都是用来重定义 this 这个对象

这里简单说一下这三个东西的用法和区别,太过深层的东西就不深究了,先用熟练,会用,再深入了解原理。

简单来说这三个东西都是用来修改this指向的,为什么要改变this指向?

案例1:

1
2
3
4
5
6
7
8
9
var name = 'AliveSeven' , age = 21
var obj = {
name : '步君',
sayName : function(){
console.log(this.name)
}
}
obj.sayName() // 步君,this指向obj对象
setTimeout(obj.sayName,0); // AliveSeven,this指向window对象

可以看出来,正常调用obj的话,this的指向是没有问题的,但是放到setTimeout中做回调问题就出现了,因为setTimeout因此回到主栈执行时是在全局执行上下文的环境中执行的,这时候this指向自然是window,这显然不符合我们的需求,因此便需要改变this的指向。

案例2:

1
2
3
4
5
6
7
8
9
10
var name = 'AliveSeven' , age = 21
var obj = {
name : '步君',
secAge : this.age,
Fn : function(){
console.log(this.name + "的年龄" + this.age);
}
}
console.log(obj.secAge) // 21
obj.Fn() // 步君的年龄undefined

关于Js中的this指向问题,可以参考下面这篇文章

https://aliveseven.github.io/posts/9170747e/

在上面代码的基础上,加入

1
2
3
4
5
6
7
8
// 声明一个data的变量
var data = {
name : '七海',
age : 77
}
obj.Fn.call(data) // 七海的年龄77
obj.Fn.apply(data) // 七海的年龄77
obj.Fn.bind(data)() // 七海的年龄77

以上除了bind 方法后面多了个 () 外 ,它们的返回结果都一样

由此得出结论,bind 返回的是一个新的函数,你必须调用它才会被执行

传参情况

案例3:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var name = 'AliveSeven' , age = 21
var obj = {
name : '步君',
secAge : this.age,
Fn : function(sex , city){
console.log(this.name + "的年龄" + this.age + "是一个" + sex + "来自" + city);
}
}
console.log(obj.secAge) // 21
obj.Fn() // 步君的年龄undefined

// 声明一个data的变量
var data = {
name : '七海',
age : 77
}

调用三个不同的方法

1
2
3
4
5
6
7
obj.Fn.call(data , "girl" , "北京")  // 七海的年龄77是一个girl来自北京
obj.Fn.call(data , ["girl" , "北京"]) // 七海的年龄77是一个girl,北京来自undefined

obj.Fn.apply(data , ["girl" , "深圳"]) // 七海的年龄77是一个girl来自深圳

obj.Fn.bind(data , "girl" , "上海")() // 七海的年龄77是一个girl来自上海
obj.Fn.bind(data , ["girl" , "上海"])() // 七海的年龄77是一个girl,上海来自undefined

结论

  • call()和apply(),bind() 的第一个参数都是用来表示指定对象的
  • 区别在于他们第二个参数的使用方式是不同的
  • 使用call()、bind()方法,第一个参数是指定this是谁,后面的参数是指定函数的实参,并且call方法的参数没有限制
  • 而apply方法的参数并不是如此:第一个参数与call()用法相同,第二个参数是数组,数组中包含实参
  • call()、apply()是立即执行的,bind不是立即执行的而bind返回的是函数,需要加()才执行
  • call()和bind()传递的参数是相同的,而apply()第二个参数是数组