归根结底,this指向就一句话:谁最终调用函数,this指向谁!!!(除箭头函数)
关于这点,有三言相赠:
1、this指向的,永远只可能是对象。
2、this指向谁,永远不取决于this写在哪!而是取决于函数在哪调用。
3、this指向的对象,我们称之为函数的上下文context,也叫函数的调用者。
1、通过函数名()直接调用:this指向window
function func(){
console.log(this);
}
func(); // this--->window
2、通过对象.函数名()调用的:this指向这个对象
function func(){
console.log(this);
}
// 狭义对象
var obj = {
name:"obj",
func1 :func
};
obj.func1(); // this--->obj
// 广义对象
document.getElementById("div").onclick = function(){
this.style.backgroundColor = "red";
}; // this--->div
3、函数作为数组的一个元素,通过数组下标调用的:this指向这个数组
function func(){
console.log(this);
}
var arr = [func,1,2,3];
arr[0](); // this--->arr
4、函数作为window内置函数的回调函数调用:this指向window( setInterval、setTimeout等)
function func(){
console.log(this);
}
setTimeout(func,1000);// this--->window
//setInterval(func,1000);
5、函数作为构造函数,用new关键字调用时:this指向新new出的对象
function func(){
console.log(this);
}
var obj = new func(); //this--->new出的新obj
6、箭头函数的this
箭头函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象
function foo() {
setTimeout(() => {
console.log('id:', this.id);
}, 100);
}
var id = 21;
foo.call({ id: 42 });
//42
function Timer() {
this.s1 = 0;
this.s2 = 0;
// 箭头函数
setInterval(() => this.s1++, 1000);
// 普通函数
setInterval(function () {
this.s2++;
}, 1000);
}
var timer = new Timer();
setTimeout(() => console.log('s1: ', timer.s1), 3100);
setTimeout(() => console.log('s2: ', timer.s2), 3100);
// s1: 3
// s2: 0
上面代码中,Timer函数内部设置了两个定时器,分别使用了箭头函数和普通函数。前者的this绑定定义时所在的作用域(即Timer函数),后者的this指向运行时所在的作用域(即全局对象)。所以,3100 毫秒之后,timer.s1被更新了3次,而timer.s2一次都没更新
this指向的固定化,并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,导致内部的this就是外层代码块的this。正是因为它没有this,所以也就不能用作构造函数。由于箭头函数没有自己的this,所以当然也就不能用call()、apply()、bind()这些方法去改变this的指向
有两种场合不合适使用箭头函数
第一个场合是定义对象的方法,且该方法内部包括this。
const cat = {
lives: 9,
jumps: () => {
this.lives--;
}
}
上面代码中,cat.jumps()方法是一个箭头函数,这是错误的。调用cat.jumps()时,如果是普通函数,该方法内部的this指向cat;如果写成上面那样的箭头函数,使得this指向全局对象,因此不会得到预期结果。这是因为对象不构成单独的作用域,导致jumps箭头函数定义时的作用域就是全局作用域。
第二个场合是需要动态this的时候,也不应使用箭头函数
var button = document.getElementById('press');
button.addEventListener('click', () => {
this.classList.toggle('on');
});
上面代码运行时,点击按钮会报错,因为button的监听函数是一个箭头函数,导致里面的this就是全局对象。如果改成普通函数,this就会动态指向被点击的按钮对象。
参考链接: