首先我们要明确一点this是在函数运行时才确定其指向的,在函数执行上下文中的另一个属性原型链是在函数定义时就确定的。this只取决于函数的调用方式。
我们通过几个例子来解析一下this是如何确定的。
- 函数调用位置在
全局上下文
function foo() {
console.log( this.a );
}
var a = 2;
foo(); //2
2.函数调用时,是否是通过对象属性调用的,或者说是否被某个对象拥有或者包 含,不过这种说法可能会造成一些误导。这时this执行调用函数的对象,即obj对象
var a = 10;
function foo() {
console.log( this.a );
}
var obj = {
a: 2,
foo: foo
};
obj.foo(); // 2
对象属性引用链中只有最顶层或者说最后一层会影响调用位置。举例来说:
function foo() {
console.log( this.a );
}
var obj2 = {
a: 42,
foo: foo
};
var obj1 = {
a: 2,
obj2: obj2
};
obj1.obj2.foo(); // 42
3.构造函数里的this指向新建的对象
function foo(a) {
this.a = a;
console.log(this);
}
var bar = new foo(2);
4.箭头函数的this,与普通函数不同,它会捕获其所在(即定义的位置)上下文的this值, 作为自己的this值。它最大的好处,解决了匿名函数的this指向问题,有利于封装回调函数。
普通函数:
var name = 'window'; // 其实是window.name = 'window'
var A = {
name: 'A',
sayHello: function(){
console.log(this.name)
}
}
A.sayHello();// 输出A
var B = {
name: 'B'
}
A.sayHello.call(B);//输出B
A.sayHello.call();//不传参数指向全局window对象,输出window.name也就是window
箭头函数:
例子一:
var name = 'window';
var A = {
name: 'A',
sayHello: () => {
console.log(this.name)
}
}
A.sayHello();// 还是以为输出A ? 错啦,其实输出的是window
例子二:
var obj = {
i: 10,
b: () => console.log(this.i, this),
c: function() {
console.log( this.i, this)
}
}
obj.b(); // undefined window{...}
obj.c(); // 10 Object {...}
例子三:
function Person() {
this.age = 0;
setTimeout(function() {
console.log(this);
});
}
var p = new Person();// window 对象
5.其它特殊情况this的判断,闭包里的调用obj.t2(),因为闭包并不属于这个对象的属性或方法。所以在闭包中的this是指向window的
var a = 10
function fn() {
return this.a
}
var obj = {
a: 5,
t1: fn, // obj.t1() 结果是5
t2: function() {
return fn()
},//obj.t2() 结果是 10
t3: function() {
return this.a
},// obj.t3() 结果是5
t4: () => this.a, //obj.t4() 结果是10 普通this是哪个对象最近调用的是哪个,箭头函数的编译时就定义好的。
}
函数赋值的情况也会导致this指向变化:
function foo() {
console.log( this.a );
}
var obj = {
a: 2,
foo: foo
};
var bar = obj.foo; // 函数别名!
var a = "oops, global"; // a 是全局对象的属性
bar(); // "oops, global"