让你快速确定 javascript 中 this指向 !

141 阅读3分钟

this的确定很多是取决于它的执行环境和它是如何执行的、但也有特例。

!!!!以下我们都从非严格模式下的出发判断的!!!! 首先非严格模式下的this不会是undefined和null,是window。 严格模式下this则会出现这两个值。 在严格模式下的undefined和null 在非严格模式下指向window。

首先让我们从箭头函数看起

一、箭头函数

我们常说箭头函数中没有this 他的this取决于它被创建时,它所处的环境中的this。这么说虽然有些宽泛但还是正确的。

让我们看一段代码

    let func = ()=>{
        console.log(this)
    }
    let obj = {
        a:function(){
            console.log(this) //{a:f}
            func()
        }
    }
    obj.a()//window

从这段代码,我们可以看出箭头函数的func中的this 在创建时就已经确定了。

所以在我们发现是箭头函数时候 只需要找到它的声明环境就可以啦

二、通过 “对象.” 访问时候

这里要注意 只要是通过 “对象.” 访问的函数它的this就指向这个对象。

    let obj = {
        a:function(){
            console.log(this) //{a:f}
        }
    }
    obj.a() //{a:f}

其实这么说还是不太严谨 、我猜大家也会想如果对象中的方法是一个箭头函数呢?

    let obj = {
        a:()=>{
            console.log(this) //window
        }
    }
    obj.a() //window

通过上面这段代码我们可以看出这样的话this的指向 取决于 箭头函数,而不再取决于 “对象.”

因此我们确定箭头函数的优先据是最高的,因此下方提及的都不包含箭头函数

让我能给我们再看一段代码

      function func() {
        console.log(this);
      }
      let obj = {
        name: "123",
      };
      obj.a = func;
      obj.a(); //{name: '123', a: ƒ}
     ---------------------------
      let func = () => {
        console.log(this);
      };
      let obj = {
        name: "123",
      };
      obj.a = func;
      obj.a(); //window

上方的两段代码 也都符合之前说的规则。所以我们的判断是没错的。 综合我们也可以看出一(箭头函数)的优先级要高于二(对象.)

三、函数的直接调用

直接调用函数的其this指向window。

      function func() {
        console.log(this);
      }
      func()//window

我们看两个特别的情况 (以下情况也属于函数的直接调用)

    let obj ={
        a:function(){
            console.log(this) //{a: ƒ}
            function fun(){
                console.log(this)//window
            }
            fun()
        }
    }
    obj.a()
    let obj = {
        a:function(){
            console.log(this)
        }
    }
    obj.a() //obj
    let fun = obj.a;
    fun()//window

四、new

当我们用new来调用构造函数时候、构造函数中的this就一定指向这个新创建的对象。

  function func() {
    this.name = "aaa";
    this.func = function () {
        console.log(this)
    };
  }
  let p = new func();
  p.func()//func {name: 'aaa', func: ƒ}
  console.log(p.name);//aaa

注意:箭头函数不可以用new关键字调用

  const func = () => {
    this.name = "aaa";
    this.func = function () {
      console.log(this);
    };
  };
  let p = new func();
  //Uncaught TypeError: func is not a constructor

五、bind、apply、call

先让我们温习一下这三个的基本知识

  • 它们三个都可以用来改变方法的中this的指向。

call、apply和bind的区别

  1. call 和 apply都会自动的调用方法,而 bind 只会修改this指向但不会自动调用方法。
  2. call 、 bind 传参数直接跟在this后依次写,而apply则需要以数组形式传参。
  //bind
  function func ()  {
    console.log(this)
  };
  let a = 1,b = 2;
  func.bind(a)() //Number {1}
  func.bind(a).bind(b)();////Number {1}
  //我们可以看出多次bind 只会响应第一次bind的this
  ------------------------------
  //apply
  func.apply(a) //Number {1}
  func.apply(a).apply(b);//Number {1}  Uncaught TypeError: Cannot read properties of undefined (reading 'apply')
  ------------------------------
  //call
  func.call(a) //Number {1}
  func.call(a).call(b);//Number {1}  Uncaught TypeError: Cannot read properties of undefined (reading 'call')

由上可看出只有 bind可以多次bind 并且其只响应第一次的。

接下来让我们对比一下 bind和apply、call的优先级

  function func() {
    console.log(this);
  }
  let a = 1,
    b = 2;
  func.bind(a).apply(b);//Number {1}
  func.bind(b).call(a)//Number {2}

我们可以看出 bind要优先级高于apply 和 call

六、全局下的this指向window 这里不在赘述啦!!!

最后最后让我们总结一下规律:

箭头函数、new、bind、apply 和 call、对象.(obj.)、直接调用。 从高到低依次确定this的指向。