this指向

彻底搞懂JavaScript中的this指向问题.


this 的指向大致可以分为下面四种:

  • 作为对象的方法调用。
  • 作为普通函数调用
  • 构造器调用
  • Function.prototype.call 或者 Function.prototype.apply 调用。

作为对象的方法调用

当函数作为对象的方法调用时,this 指向这个对象:

const obj = {
  a: 1,
  getA() {
    console.log(this === obj); // true
    console.log(this.a); // 1
  },
};

要注意,如果 getA 是箭头函数的话,this 指向 window,箭头函数没有自己的 this,它会继承外部作用域的 this 值。

const obj = {
  a: 1,
  getA: () => {
    console.log(this === obj); // false
    console.log(this); // 指向window对象
  },
};

作为普通函数调用

当函数不作为对象的属性被调用时,此时的 this 指向全局对象,在浏览器的 JavaScript 里,全局对象是 window,在 Node 环境中,全局对象是 global :

window.name = "globalName";
const getName = function () {
  return this.name;
};

console.log(getName()); // globalName

构造器调用

JavaScript 中没有类,但是可以从构造函数中创建对象,通过 new 运算符调用函数时,会返回一个对象,通常情况下,构造器里的 this 就指向这个返回的对象:

const MyClass = function() {
    this.name = '张三';
    return {
        name: '李四';
    }
}

const obj = new MyClass();
console.log(obj.name); // 李四

上面的代码打印输出 李四 ,因为构造函数返回了一个对象,如果构造函数不显示地返回任何数据,或者返回一个非对象类型的数据,就不会造成上面的问题:

const MyClass = function () {
  this.name = "张三";
  return "李四";
};

const obj = new MyClass();
console.log(obj.name); // 李四

Function.prototype.call 或者 Function.prototype.apply 调用

跟普通函数调用相比,Function.prototype.call 或 Function.prototype.apply 可以动态地改变 this 的指向:

const obj1 = {
  name: "张三",
  getName() {
    return this.name;
  },
};

const obj2 = {
  name: "李四",
  getName() {
    return this.name;
  },
};

console.log(obj1.getName()); // 张三
console.log(obj1.getName.call(obj2)); //李四

call 和 apply 方法能很好地体现 JavaScript 的函数式语言特性,每一次编写函数式风格的代码,都离不开 call 和 apply。