结论:
一 :在一个函数上下文中,this由调用者提供,由调用函数的方式来决定。如果调用者函数,被某一个对象所拥有,那么该函数在调用时,内部的this指向该对象。如果函数独立调用,那么该函数内部的this,则指向undefined。但是在非严格模式中,当this指向undefined时,它会被自动指向全局对象。
从结论中我们可以看出,想要准确确定this指向,找到函数的调用者以及区分他是否是独立调用就变得十分关键。
// demo01
var a = 20;
function fn() {
console.log(this.a);
}
fn(); //fn()是调用者,为独立调用,非严格模式下指向全部对象window,因此结果为20
// demo02
var a = 20;
function fn() {
function foo() {
console.log(this.a);
}
foo();
}
fn(); //fn()是调用者,为独立调用,非严格模式下指向全部对象window,因此结果为20
// demo03
var a = 20;
var obj = {
a: 10,
c: this.a + 20,
fn: function () {
return this.a;
}
}
console.log(obj.c); // 对象obj中的c属性使用`this.a + 20`来计算。这里我们需要明确的一点是,单独的`{}`是不会形成新的作用域的,因此这里的`this.a`,由于并没有作用域的限制,所以它仍然处于全局作用域之中。所以这里的this其实是指向的window对象,因此结果为40。
console.log(obj.fn()); //fn()是调用者,他不是独立调用,被对象obj所调用,因此它的this指向指向obj因此结果为10
再来看一些容易理解错误的例子,加深一下对调用者与是否独立运行的理解。
var a = 20;
var foo = {
a: 10,
getA: function () {
return this.a;
}
}
console.log(foo.getA()); // 10
var test = foo.getA;
console.log(test()); // 20
foo.getA()
中,getA是调用者,他不是独立调用,被对象foo所拥有,因此它的this指向了foo。而test()
作为调用者,尽管他与foo.getA的引用相同,但是它是独立调用的,因此this指向undefined,在非严格模式,自动转向全局window。
稍微修改一下代码,大家自行理解。
var a = 20;
function getA() {
return this.a;
}
var foo = {
a: 10,
getA: getA
}
console.log(foo.getA()); // 10
灵机一动,再来一个。如下例子。
function foo() {
console.log(this.a)
}
function active(fn) {
fn(); // 真实调用者,为独立调用
}
var a = 20;
var obj = {
a: 10,~~~~
getA: foo
}
active(obj.getA); // 20
二:使用call,apply显示指定this
JavaScript内部提供了一种机制,让我们可以自行手动设置this的指向。它们就是call与apply。所有的函数都具有着两个方法。它们除了参数略有不同,其功能完全一样。它们的第一个参数都为this将要指向的对象。
如下例子所示。fn并非属于对象obj的方法,但是通过call,我们将fn内部的this绑定为obj,因此就可以使用this.a访问obj的a属性了。这就是call/apply的用法。
function fn() {
console.log(this.a);
}
var obj = {
a: 20
}
fn.call(obj); //结果为20
三:箭头函数 this指向
箭头函数中,没有this。如果你在箭头函数中使用了this,那么该this一定就是外层的this。也正是因为箭头函数中没有this,因此我们也就无从谈起用call/apply/bind来改变this指向。
在ES6中,会默认采用严格模式,因此this也不会自动指向window对象了,而箭头函数本身并没有this,因此this就只能是undefined,这一点,在使用的时候,一定要慎重慎重再慎重,不然踩了坑你都不知道自己错在哪!这种情况,如果你还想用this,就不要用使用箭头函数的写法。
箭头函数 this指向是在定义的时候处在的对象就是它的this。箭头函数的this看外层的是否有函数,如果有,外层函数的this就是内部箭头函数的this,如果没有,则this是window。
var a = 10;
var obj = {
a:99,
fn1: () => {
console.log(this.a)},
fn2:function () {
console.log(this.a)}
}
obj.fn1(); //10
obj.fn2(); //99
let btn1 = document.getElementById('btn1');
let obj = {
name: 'kobe',
age: 39,
getName: function () {
btn1.onclick = () => {
console.log(this);//obj
};
}
};
obj.getName();
上例中,由于箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this。
那假如上一层并不存在函数,this指向又是谁?
let btn2 = document.getElementById('btn2');
let obj = {
name: 'kobe',
age: 39,
getName: () => {
btn2.onclick = () => {
console.log(this);//window
};
}
};
obj.getName();
上例中,虽然存在两个箭头函数,其实this取决于最外层的箭头函数,由于obj是个对象而非函数,所以this指向为Window对象
参考文章:
全方位解读this
你还没搞懂this
典型面试例子及答案:
// 修改$对象里面的代码,使得以下代码运行正常
var $ = {
fn:function () {
console.log(1);
},
fn2:function () {
console.log(2);
}
}
$.fn().fn2();
// 答案:
var $ = {
fn:function () {
console.log(1);
return this; // 返回this,可以继续调用函数
},
fn2:function () {
console.log(2);
}
}
$.fn().fn2();
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。