js的this

192 阅读3分钟

归根结底,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就会动态指向被点击的按钮对象。

参考链接:

www.cnblogs.com/huangwentia…

www.ruanyifeng.com/blog/2010/0…

es6.ruanyifeng.com/#docs/funct…