理清 js 中的 this

JavaScript 中的 this 的指向,完全取决于调用的方式.

思维导图 1.png

调用

全局调用

1
console.log(this); //全局对象,在浏览器中为 window 对象,在 nodejs 中为 global,方便起见,后面我们都是在浏览器中运行,即全局对象为 window

直接作为函数调用

函数可以被直接调用,这时 this 指向全局对象.比如下面的例子:

1
2
3
4
5
6
7
8
function f1(a1) {
this.a1 = a1;
}

f1(1);

console.log(window.a1); //1
//a1 已经成为一个全局对象

注意在全局模式中,函数的 this 为 undefined,因为严格模式禁止 this 关键字指向全局对象.因此:

1
2
3
4
5
6
7
8
"use strict";
function f1(a1) {
this.a1 = a1;
}

f1(1);

console.log(window.a1); //undefined

作为对象的方法调用

在 JavaScript 中,函数也是对象,因此函数也可以作为对象的一个属性,此时这个函数被称为这个对象的方法,在这个方法中使用的 this 指向当前的对象.

1
2
3
4
5
6
7
8
9
10
var point = {
x: 0,
y: 0,
moveTo: function(x, y) {
this.x = this.x + x;
this.y = this.y + y;
}
};

point.moveTo(1, 1); //this 绑定到当前对象,即 point 对象

对于内部函数,即声明在另外一个函数体内的函数,这种绑定到全局对象的方式会产生另外一个问题。我们仍然以前面提到的 point 对象为例,这次我们希望在 moveTo 方法内定义两个函数,分别将 x,y 坐标进行平移。结果可能出乎大家意料,不仅 point 对象没有移动,反而多出两个全局变量 x,y。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var point = {
x: 0,
y: 0,
moveTo: function(x, y) {
// 内部函数
var moveX = function(x) {
this.x = x; //this 绑定到了哪里?
};
// 内部函数
var moveY = function(y) {
this.y = y; //this 绑定到了哪里?
};

moveX(x);
moveY(y);
}
};
point.moveTo(1, 1);
point.x; //==>0
point.y; //==>0
x; //==>1
y; //==>1

这属于 JavaScript 的设计缺陷,正确的设计方式是内部函数的 this 应该绑定到其外层函数对应的对象上,为了规避这一设计缺陷,聪明的 JavaScript 程序员想出了变量替代的方法,约定俗成,该变量一般被命名为 that。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var point = {
x: 0,
y: 0,
moveTo: function(x, y) {
var that = this;
// 内部函数
var moveX = function(x) {
that.x = x;
};
// 内部函数
var moveY = function(y) {
that.y = y;
};
moveX(x);
moveY(y);
}
};
point.moveTo(1, 1);
point.x; //==>1
point.y; //==>1

作为构造函数调用

构造函数的目的是构造对象,因此 this 的指向即为新构造的对象.

1
2
3
4
5
6
7
8
9
10
"use strict";

function F1() {
this.x = 1;
this.y = 2;
}

let a1 = new F1();

console.log(a1); //{x:1,y:2}

但是需要注意的是,如果忘记加 new的话 ,构造函数中的 this 仍然是指向 window 的(在严格模式中为 undefined)

1
2
3
4
5
6
function F1() {
return this;
}

let a2 = F1();
console.log(a2); //window

作为 class 中调用

es5 中添加了 class 的概念,其实就是构造函数的语法糖,因此在 class 中 this 的指向与在构造函数中 this 的指向相同.

改变 this 的指向

箭头函数

箭头函数的 this 始终指向函数定义时的 this,而非执行时。,箭头函数需要记着这句话:“箭头函数中没有 this 绑定,必须通过查找作用域链来决定其值,如果箭头函数被非箭头函数包含,则 this 绑定的是最近一层非箭头函数的 this,否则,this 为 undefined”。

在函数内部使用 _this

先将调用这个函数的对象保存在变量 _this 中,然后在函数中都使用这个 _this,这样 _this 就不会改变了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var name = "windowsName";

var a = {
name: "Cherry",

func1: function() {
console.log(this.name);
},

func2: function() {
var _this = this;
setTimeout(function() {
_this.func1();
}, 100);
}
};

a.func2(); // Cherry
thank u !