JS|this

148 阅读2分钟

追本溯源:this

首先看mdn中的解释:在绝大多数情况下,函数的调用方式决定了this的值,this不能在执行期间被赋值,并且在每次函数被调用时this的值也可能会不同。

重点:函数的调用方式决定了this的值,也就是说this在绝大多数的情况下指向调用它的那个对象

其实在我们实际编码中,经常会使用this.xxx,有时候就会出现this.xxx is undefined的错误。就是有时候代码执行上下文中的this并不是我们想当然的那个对象。

ES5引入了bind方法来设置函数中的this的值,而不用考虑函数是如何被调用的。ES6引入了箭头函数,箭头函数不提供自身的this绑定

无论在何处我们都可以直接使用globalThis来获取全局对象

function someFunction() {
  return this;
}

// `true`:
console.log(someFunction() === globalThis);

其实this是和执行上下文绑定的,所以this也可以分为三种:

  • 全局上下文中的this
  • 函数上下文中的this
  • eval中的this(基本不使用)

根据mdn的定义我们知道了,绝大多数都是指向调用他的那个对象除了绝大多数的情况,还有一些特殊的情况需要单独注意一下:

  1. 箭头函数(arrow function):与外部的this相同
const outerThis = this
const arrowFunction = () => {
  console.log(this === outerThis)
}
arrowFunction()		// true

一些其他的情况:

  • bind:不会改变this指向

  • call/apply:不会改变this指向

  • 作为其他Object的属性被调用:不会改变this指向

    const obj = {arrowFunction};
    // `true`
    obj.arrowFunction();
    
  • 使用new调用函数:

    new arrowFunction()  
    // TypeError: arrowFunction is not a constructor
    
    • class中使用箭头函数:this总是指向class的实例
    class Whatever {
      someMethod = () => {
        // 总是指向Whatever的实例
        console.log(this);
      };
    }
    

    总的来说,如果使用了箭头函数,函数内的this就基本上指向外部的this

  1. new:等价于Object.create(Whatever.prototype)

    • bindthis指向不会被改变

      const BoundMyClass = MyClass.bind({foo: 'bar'});
      new BoundMyClass();
      
    • 作为其他Object的属性被newthis指向不会被改变

      const obj = {MyClass};
      // Logs `true` - parent object is ignored:
      new obj.MyClass();
      
  2. 使用call apply bind

    • call apply可以指定一个this值和单独给出一个或者多个参数来调用一个函数
    • bind会创建一个新函数,这个新函数的this是指定的

参考文章: what is this