this关键字

摘要:this关键字,网上已经有好多关于它的文章,但是笔者还是希望通过自己的梳理来加深理解^_^前端的小伙伴肯定都十分了解,平常做项目的时候可能都会用到,有时也怕进了自己的圈套而尽量少用。下面看看this在各种环境下到底它是啥??

this关键字:上下文

一.全局上下文

当在全局环境下,此时的this指向window对象,全局中的this如此,全局函数中的this也是如此。当然node下指向的是global。(这里我们都是以浏览器为例~)

1
2
3
4
5
6
7
console.log(this);	//window
console.log(this); //global(node)

function fun(){
console.log(this);
}
fun();//window

二.对象的方法

调用对象的方法,此时方法中的this指向调用对象,下面代码中obj.fun(),fun是由obj调用的,所以fun中的this指向obj。但是把对象的方法赋值给一个对象后,即fun1,再调用该方法,此时的this就指向了window,因为此时的fun1为一个普通函数,调用对象为window,所以this就指向了window。

1
2
3
4
5
6
7
8
9
var obj = {
fun: function(){
console.log(this);
}
}
obj.fun();//obj

var fun1 = obj.fun;
fun1();//window

1.对象方法中this指向window的情况

同样,我们来看看下面这个例子,在obj.fun中定义函数,然后再调用,这个的道理上面的是一样的,由于f是一个普通函数,而且没有对象调用它,所以调用对象为window,此时的this同样指向this。window对象调用的方法,少不了的还有自动执行函数,它的this也是指向window。

1
2
3
4
5
6
7
8
9
var obj = {
fun:function(){
function f(){
console.log(this);
}
f();
}
}
obj.fun();//window

1
2
3
4
5
6
7
8
var obj = {
fun:function(){
(function(){
console.log(this);
})();
}
}
obj.fun();//window

2.setTimeout中的this

1
2
3
4
5
6
7
8
var obj = {
fun: function(){
setTimeout(function(){
console.log(this);
},100);
}
}
obj.fun();//window

上面这段代码,setTimeout中传入的function也是一个普通函数,所以函数中的this还是指向window,那么怎样在setTimeout的函数中使用this呢?这是后闭包就派上用场了~

1
2
3
4
5
6
7
8
9
var obj = {
fun: function(){
var that = this;
setTimeout(function(){
console.log(that);
},100);
}
}
obj.fun();//obj

三.构造函数

1
2
3
4
5
6
7
8
function FOO(a){
this.a = a;
this.fun = function(){
console.log(this.a);
};
}
var foo = new FOO(13);//foo
foo.fun();//13

这里先解释一下new的用法,更便于理解,new:其实是生成了一个空对象,然后把this指向该对象。
foo为FOO的实例对象,这里上面的代码就不难解释了,foo调用fun,所以this就指向了foo。这里有一点需要注意,当构造函数有返回值的时候,new出来的对象为返回的对象,而当构造函数没有返回值的时候,new出来的对象才为实例化的对象。

1
2
3
4
5
6
7
8
9
function FOO(a){
this.a = a;
this.fun = function(){
console.log(this.a);
};
return {a:1};
}
var foo = new FOO(13);// {a:1}
foo.fun();//foo.fun is not a function

四.原型链中的this

1
2
3
4
5
6
7
8
var obj = {
fun : function(){
console.log(this);
}
};
var foo = Object.create(obj);
foo.a = 1;
foo.fun();//foo

foo其实没有fun方法,但是foo继承obj,所以会从原型链上查找,找到fun后执行,这时因为fun是foo调用的,所以此时的this指向foo。

五.箭头函数

ES6的箭头函数是比较特殊的,因为箭头函数的this是在函数定义时就确定的,为什么会这样呢?其实箭头函数根本就没有this,所以说他的this是在定义的确定的,其实是它的this其实是外层的this,所以就是其定义时的this,下面来看看他的特殊之处。

1
2
3
4
5
6
7
8
9
var obj = {
fun: function(){
var foo = () => {
console.log(this);
}
foo();
}
}
obj.fun();//obj

1
2
3
4
5
6
7
8
var obj = {
fun: function(){
setTimeout(() => {
console.log(this);
},100);
}
}
obj.fun();//obj

无论是对象方法中的函数还是setTimeout传入的函数,此时的this都指向了obj对象,就是因为箭头函数的this是在函数定义时就确定的,并且它的this不能被改变。但是有一点需要注意的是箭头函数不能直接作为对象的方法,如果这样做的话,oh no ,此时的this还是指向了window。

1
2
3
4
5
6
var obj = {
fun: () => {
console.log(this);
}
}
obj.fun();//window

六.严格模式下的this

全局函数中的this指向为undefined

1
2
3
4
5
'use strict';
function fun(){
console.log(this);
}
fun();//undefined

严格模式下setTimeout函数中的this默认指向window,咦,这跟我们上面所说的好像不一样耶??其实因为严格模式下setTimeout传入的函数默认会执行fun.apply(window);使函数的this指向window对象,如果传入的函数有绑定this则为绑定的this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
'use strict';
var obj1 = {
a:1
}
var obj = {
fun1: function(){
setTimeout(function(){
console.log(this);
},100);
},
fun2: function(){
setTimeout((function(){
console.log(this);
}).call(obj1),100);
}
}
obj.fun1();//window
obj.fun2();//obj1

七.修改this指向

那么如何修改this呢?js中提供了如下三种方法~~~~其实这三个方法的功能是相似的,都是为方法指定this对象,只不过call跟apply都是立即执行的,而bind方法是返回一个新函数,该函数指定this上下文。

1
2
3
fun.call(this,a,b,c,...);
fun.apply(this,[a,b,c,...]);
var foo = fun.bind(this,a,b,c,...);

八.DOM事件处理函数中的this

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
<div id="item">
<div>aaa</div>
</div>

document.getElementById('item').onclick = function(e){
console.log(this);
<!--
<div id="item">
<div>aaa</div>
</div>
-->
console.log(e.target);
<!--
<div>aaa</div>
-->
console.log(e.currentTarget == this);
<!--true-->
}

<div id="item" onclick="console.log(this);">
<div>aaa</div>
</div>
<!--<div id="item" onclick="console.log(this);">
<div>aaa</div>
</div>-->

DOM事件处理函数中的this指向触发事件的元素,也就是e.currentTarget
内联事件处理函数中的this,当然指向了他本身

end

当然我们也可以比较简单的来看this,看到底是谁调用的,是谁调用,this就指向谁~~