JavaScript中的this指向问题总结

327 阅读3分钟

根据MDN文档及相关博客总结一下this在各种情况下的指向问题。基本规则有三条:

  • 函数中的this指向调用它的对象
  • 箭头函数的this指向为定义时外部上下文的this指向
  • call,bind,apply函数调用的函数this指向为第一个参数

全局上下文

在全局状态下this指向全局对象,浏览器端指向window,node端指向globalThis

console.log(this===window) // true

函数中的this

对象调用函数,函数中的this指向最近的调用它的对象,函数前没有对象则视为全局对象调用函数

var a = 1;
var b = {
  a: 2,
};
function print() {
  console.log(this.a);
}
print() // 1 指向window
b.x=print
b.x(); // 2 指向b

使用call,bind,apply函数调用的函数this指向为第一个参数

  • apply(obj,args)
var a = 1;
var b = {
  a: 2,
};
function print(x,y) {
  console.log(this.a+x+y);
}
print.apply(b,[3,5]) // 10 this指向b
  • call(obj,...args)
var a = 1;
var b = {
  a: 2,
};
function print(x,y) {
  console.log(this.a+x+y);
}
print.apply(b,3,5) // 10 this指向b
  • bind(obj,...args) 使用bind函数绑定过后函数的this将永久被改变,无论调用方式如何,总是指向绑定的对象。已经被bind过的函数不会再bind到其他对象上。
    var b = {
      a: 2,
    };
    var c = {
      a: 3,
    };
    function print() {
      console.log(this.a);
    }
    c.say = print.bind(b);
    c.say() // 2 this被绑定到b
    b.say= c.say.bind(c)
    b.say() // 2 第二次bind不会生效

箭头函数中的this

箭头函数没有自己的this,他的this继承自外部函数,指向创建时的外部函数的this。不能够直接改变箭头函数的this(如bind函数等),但可以通过改变外部函数的this指向间接改变箭头函数this指向

  • 在全局创建一个箭头函数
    let fn = () => {
      console.log(this === window); // true
    };
    let a = {};
    fn();
    a.print = fn;
    a.print(); // true this始终指向创建时指向的window
  • 对象中创建箭头函数
var obj = {
  bar: function() {
    var x = (() => this);
    return x;
  }
};
var fn = obj.bar();

// 直接调用fn而不设置this,
// 通常(即不使用箭头函数的情况)默认为全局对象
console.log(fn() === obj); // true

// 但是注意,如果你只是引用obj的方法,而没有调用它
var fn2 = obj.bar;
// 那么调用箭头函数后,this 指向 window,因为 bar 的 this 指向 window,箭头函数从 bar 继承了this。
console.log(fn2()() == window); // true

函数作为对象的属性

  • 函数作为对象属性时,this指向仍由调用函数的对象决定
  • 函数在对象的原型链上,概念仍然适用
var o = {
  f: function() {
    return this.a + this.b;
  }
};
var p = Object.create(o); // p的原型上有方法f
p.a = 1; 
p.b = 4;

console.log(p.f()); // 5 虽然方法在原型上,但调用者仍然是p

函数作为构造函数

函数作为构造函数调用时,this指向实例化后的对象。

function a(value) {
  this.value = value;
  this.fn = function () {
    console.log(this.value);
  };
}
let obj1 = new a(10);
obj1.fn();// 10

谨记:this指向调用函数的对象

事件处理函数的this

addEventListener添加事件处理函数,或者内联事件函数,函数的this指向绑定事件的元素(this===event.currentTarget始终为true),例如给父元素添加click事件监听,点击子元素,this指向父元素,而不是被点击的子元素