this的指向问题
初步了解this的指向
在JavaScript中,this的指向在函数定义时是无法确定的。只有在函数执行时才能确定。初步的
可以认为JavaScript中的this指向最后一个调用它的对象
例子1
1 | function exp1() { |
在此例中exp1函数事实上是被window对象调用的,我们所创建的变量函数都是window的属性,因而this的指向是window
更进一步了解
但事实上也存在与上面例子不同的情况
例子21
2
3
4
5
6
7var a = {
name:'phil',
fn: function () {
console.log(this.name);//phil
}
}
window.a.fn()
例子31
2
3
4
5
6
7
8
9
10var b = {
b1: 'phil',
b2: {
b1: 'Pphil',
bb2: function () {
console.log(this.b1);//Pphil
}
}
}
b.b2.bb2()
通过以上三个例子可以看出,初步结论并不一定对。其实this的指向分为三种情况
- 如果函数中this,但没有被上一级调用,那么this指向window(严格模式不算,因为严格模式会屏蔽this指向全局对象)
- 如果一个函数中有this,这个函数有被上一级的对象所调用,那么this指向的就是上一级的对象。
- 如果一个函数中有this,这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象
例子41
2
3
4
5
6
7
8
9
10
11
12var o = {
a:10,
b:{
a:12,
fn:function(){
console.log(this.a); //undefined
console.log(this); //window
}
}
}
var j = o.b.fn;
j();
为什么这里又是window而不是上一级对象呢,因为需要看最后函数执行的时候是谁在调用它。这里将fn赋值给变量j的时候并没有执行,j是一个全局变量所以最后是windiow
构造函数中的this
例子51
2
3
4
5
6function exp5(){
this.name = 'phil';
}
var p = new exp5();
console.log(p.name);//phil
这里最后调用的是p,p是全局对象但new关键字会改变this的指向
例子61
2
3
4
5
6function fn() {
this.name = 'phil';
return {}
}
var q = new fn();
console.log(q.name);//unfinded
当return一个对象时,return则指向那个对象,不是对象(但包括null)则还是指向原来的函数
this与settime
改变this指向 call apply bind
call apply bind都可以改变this的指向,但都有各自不同的地方
call
call可以把参数的环境添加到调用的对想象中
1 | var a = { |
call也可以支持多个参数,用逗号分割
o.call(a,x,xx,xxx)
apply
apply与call功能相同,但是第二个参数必须以数组的形式
o.apply(a,[x,xx,xxx])
bind
bind并不会像call和apply那样直接执行而是返回一个函数1
2
3
4
5
6
7
8
9var a = {
name: 'phil',
skill: function () {
console.log(this.name);
}
}
var o = a.skill;
var c = o.bind(a)
c()//phil
定时器中的this
匿名函数,定时器中的函数,由于没有默认的宿主对象,所以默认this指向window1
2
3
4
5
6
7
8var obj = {
say: function () {
setTimeout(function () {
console.log(this)//window
});
}
}
obj.say();
如果要在setTimeout/setInterval中使用this可以采用以下方法
保存this
1
2
3
4
5
6
7
8
9
10
11var obj = {
func: function() {},
say: function () {
var that = this; //此时的this就是obj对象
setTimeout(function () {
console.log(this)
that.func()
});
}
}
obj.say();使用bind函数给回调函数绑定宿主对象
1
2
3
4
5
6
7
8
9
10
11var obj = {
func: function() {},
say: function () {
// 此时的this就是obj对象
setTimeout(function () {
console.log(this)
this.func()
}.bind(this));
}
}
obj.say(); // obj
一道练习
1 | window.val = 1; |
第一次调用时this.val的指向时obj,val变量在没有指定对象前缀,默认从函数中找,找不到则从window中找全局变量
因此结果是1
2
3
4
5
6
7
8
9
10window.val = 1;
var obj = {
val: 2,
dbl: function () {
this.val *= 2;//2*2=4
val *= 2;//1*2
console.log(val);//2
console.log(this.val);//4
}
};
第二次调用时func是全局变量所以最后的调用对象是window,this指向window
1 | var obj = { |
es6箭头函数中的this
箭头函数中其实没有this,都是通过继承而来,严格模式下,没有宿主调用的函数中的this是undefined,所以箭头函数中的也是undefined。1
2
3
4
5
6
7
8var obj = {
say: function () {
setTimeout(() => {
console.log(this)
});
}
}
obj.say(); // obj
这个时候this继承自obj,所以指向obj