this、apply、call and bind

本篇文章会详细讲解JavaScript中的this相关的问题。

[1] 如果你在阅读中发现错误或者存在某些问题可以通过邮件的形式发送到作者的邮箱,再收到邮件后作者会及时处理这些问题。

[2] 阅读文章后你能了解到的有this 指向、apply、call和bind方法。


this

在深入了解this前,我们要知道this在调用函数时能够控制使用不同的上下文环境,同时this永远指向最后调用它的对象,在EcmaScript中已经有效的规避的this容易产生的错误,但是在我们阅读某个框架源码的时候,还是要深入了解下this


理解this指向

我们通过例子去理解this指向的问题。

例如我们拥有一个USER的对象,并且通过点号的形式进行调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const USER = {
name: 'Taylor',
age: 34,
greet() {
console.log(`name: ${USER.name}`)
console.log(`name: ${this.name}`)
}
}
USER.greet()
// 输出结果:
// name: Taylor
// name: Taylor

可以看到我们在调用方法的时候相当于把this指向了USER对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
const STUDENT = {
name: 'Taylor',
age: 12,
greet() {
console.log(`name: ${STUDENT.name}`)
console.log(`name: ${this.name}`)
},
mother: {
name: 'Swift',
age: 35,
greet() {
console.log(`name: ${STUDENT.mother.name}`)
console.log(`name: ${this.name}`)
}
}
}
STUDENT.greet()
STUDENT.mother.greet()
// 输出结果:
// name: Taylor
// name: Taylor
// name: Swift
// name: Swift

改变this指向

能够改变this指向的操作有:

  • 箭头函数

  • 函数内部使用_this = this

  • apply

  • call

  • bind

  • new一个对象

箭头函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const OBJ = {
name: 'Taylor',
time1: function() {
setTimeout(function() {
console.log(`name: ${this.name}`) // name: windowName
}, 0)
},
time2: function() {
setTimeout(() => {
console.log(`name: ${this.name}`) // name: Taylor
}, 0)
}
}
OBJ.time1()
OBJ.time2()
函数内部使用_this = this
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const OBJ = {
name: 'Taylor',
time1: function() {
setTimeout(function() {
console.log(`NAME: ${this.name}`) // name: windowName
}, 0)
},
time2: function() {
let _this = this
setTimeout(function() {
console.log(`NAME: ${_this.name}`) // name: Taylor
}, 0)
}
}
OBJ.time1()
OBJ.time2()
apply
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const OBJ = {
name: 'Taylor',
time1: function() {
setTimeout(function() {
console.log(`NAME: ${this.name}`) // name: windowName
}, 0)
},
time2: function() {
setTimeout(function() {
console.log(`NAME: ${this.name}`) // name: Taylor
}.apply(OBJ), 0)
}
}
OBJ.time1()
OBJ.time2()
call
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const OBJ = {
name: 'Taylor',
time1: function() {
setTimeout(function() {
console.log(`NAME: ${this.name}`) // name: windowName
}, 0)
},
time2: function() {
setTimeout(function() {
console.log(`NAME: ${this.name}`) // name: Taylor
}.call(OBJ), 0)
}
}
OBJ.time1()
OBJ.time2()
bind
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const OBJ = {
name: 'Taylor',
time1: function() {
setTimeout(function() {
console.log(`NAME: ${this.name}`) // name: windowName
}, 0)
},
time2: function() {
setTimeout(function() {
console.log(`NAME: ${this.name}`) // name: Taylor
}.bind(OBJ)(), 0)
}
}
OBJ.time1()
OBJ.time2()
new绑定
1
2
3
4
5
6
function User (name, age) {
this.name = name
this.age = age
}
const func = new User('Taylor', 27)

apply和call的区别

  • apply接受一个包含多个参数的数组
  • call接受多个参数
apply传参
1
2
3
4
5
6
7
8
const OBJ ={
fn: function(a, b) {
console.log(a + b) // 3
}
}
let func = OBJ.fn;
func.apply(OBJ, [1,2])
call传参
1
2
3
4
5
6
7
8
const OBJ ={
fn: function(a, b) {
console.log(a + b) // 3
}
}
let func = OBJ.fn;
func.call(OBJ, 1, 2)

bind和apply、call的区别

bind方法创建一个新的函数, 当bind被调用时,将其this指向为bind的第一个参数,在调用新函数时提供剩余参数序列。

1
2
3
4
5
6
7
8
const OBJ ={
fn: function(a, b) {
console.log(a + b) // 3
}
}
let func = OBJ.fn;
func.bind(OBJ, 1, 2)()
------本文结束,感谢您的阅读,如有问题请通过邮件方式联系作者------