理解-Javascript的this指向问题

this指向问题通常会在一些面试题中出现,情况比较多,先了解下它的一些特点:

  • this是执行上下文的一部分
  • 需要在执行时确定
  • 浏览器中 this 指向 window, node中this指向global

对于非严格模式和es5的js程序中,this指向可以分为以下几种情况:

第一种:a()直接调用的方式,this === window

1
2
3
4
5
function a() {
console.log(this.b)
}
var b = 0
a()

打印出的值为 0

第二种:谁调用了函数,谁就是this

1
2
3
4
5
function a() {
console.log(this)
}
var obj = {a: a}
obj.a()

打印出的值为obj这个对象

第三种:构造函数模式下,this指向当前执行类的实例

1
2
3
4
5
6
function getPersonInfo(name, age) {
this.name = name
this.age = age
console.log(this)
}
var p1 = new getPersonInfo('linda', 13)

打印出来的值是:

getPersonInfo{ name: 'linda', age: 13 }

第四种:call/apply/bind调用函数的方式,this指向第一个参数

1
2
3
4
5
6
7
function add (b, c) {
console.log(this)
return this.a + b + c
}
var obj = {a: 3}
add.call(obj, 5, 7)
add.call(obj, [10, 20])

打印出来的值就是obj的值

对于严格模式的js程序中,this指向对于直接调用的方式有所不同

严格模式下,函数直接调用的方式中this指向undefined

1
2
3
4
5
'use strict'
function a() {
console.log(this)
}
a()

这个时候函数里的this打印出 undefined

对于箭头函数

箭头函数没有自身的this关键字,看外层是否有函数,如果有函数,外层函数的this就是内部箭头函数的this,如果没有,this就是指向window

可以看以下几种情况:

1
2
3
4
5
6
7
8
9
10
11
var person = {
myName: 'linda',
age:1,
clickPerson: function() {
var show = function() {
console.log(`Person name is ${this.myName}, age is ${this.age}`)
}
show()
}
}
person.clickPerson()

打印结果:Person name is undefined, age is undefined

里面的函数show被调用的时候,是普通函数调用的情况,所以this指向window,而全局函数中没有myName和age,所以打印出来是undefined

可以换成箭头函数:

1
2
3
4
5
6
7
8
9
10
11
var person = {
myName: 'linda',
age:1,
clickPerson: function() {
var show = () => {
console.log(`Person name is ${this.myName}, age is ${this.age}`)
}
show()
}
}
person.clickPerson()

打印出的结果是:Person name is linda, age is 1

对于箭头函数自身没有this关键字,所以看外层函数,而外层函数中是我们前面说到的第二种情况,this指向person这个对象,所以是有myName和age的值

如果把clickPerson也换成箭头函数:

1
2
3
4
5
6
7
8
9
10
11
var person = {
myName: 'linda',
age:1,
clickPerson: () => {
var show = () => {
console.log(`Person name is ${this.myName}, age is ${this.age}`)
}
show()
}
}
person.clickPerson()

我们发现打印的结果是:Person name is undefined, age is undefined

由于都是箭头函数,最后找到了全局的window,所以this指向window,而全局函数中没有myName和age,所以打印出来是undefined

再看另外一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function getPersonInfo(name,age){
this.myName = name;
this.age = age;
this.show = function() {
console.log(`Person name is ${this.myName}, age is ${this.age}`)
}
}
getPersonInfo.prototype.friend = function(friends) {
var array = friends.map(function(friend) {
return `my friend ${this.myName} age is ${this.age}`
});
console.log(array);
}

var person1 = new getPersonInfo("linda",18);
person1.show()
person1.friend(['Ada', 'Tom'])

show()函数调用结果打印:Person name is linda, age is 18
friend()函数调用打印结果:["my friend undefined age is undefined", "my friend undefined age is undefined"]

对于friend函数内部,this指向的是当前的getPersonInfo这个构造函数初始化的实例,但是在内部使用map是一个闭包函数,且内部是普通函数的调用方式,所以内部this是指向了window,可以把里面普通函数调用的方式改成箭头函数的方式即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function getPersonInfo(name,age){
this.myName = name;
this.age = age;
this.show = function() {
console.log(`Person name is ${this.myName}, age is ${this.age}`)
}
}
getPersonInfo.prototype.friend = function(friends) {
var array = friends.map((friend) => {
return `my friend ${this.myName} age is ${this.age}`
});
console.log(array);
}

var person1 = new getPersonInfo("linda",18);
person1.show()
person1.friend(['Ada', 'Tom'])

这次打印结果就是["my friend linda age is 18", "my friend linda age is 18"]就是我们预想的了

总结:(非严格模式下)可以按照下图规律查找this的指向

this的指向