this指向/箭头函数this指向详解

·  阅读 311

一、思考:

1.为什么不能使用箭头函数来定义methods?

答:因为箭头函数没有自己的作用域,绑定的是父级作用域的上下文,

如果使用箭头函数,那么在获取data里面的数据的时候,this指向window导致访问失败

原因:这跟this的绑定规则有关,在箭头函数中不绑定this,但是如果箭头函数使用了this,会往上层作用域去找,注意:methods对象并不是作用域(所有的对象都没有作用域)

2.不使用箭头函数的情况下,this到底指向什么?

答:vue源码通过bind显式绑定指向vue实例的proxy(代理)

二、this指向:

首先,我们必须先知道,每个函数都会有自身的this,但是this并不是在函数声明完就绑定到某个对象上的,只有在函数调用时,this才会被绑定,

也就是说,this的绑定和函数定义的位置没有关系,和函数的调用方式有关系。

常见的this指向:

  • 全局作用域中或者普通函数中this指向全局对象window
  • 立即执行函数this必定指向window
  • 定时器this指向window
  • 事件中this指向事件源对象
  • 方法中谁调用就指向谁
  • 构造函数中this指向对象实例

三、this绑定规则:

1、默认绑定规则

1.默认绑定全局对象window

console.log(this === window);   //true
复制代码

2.全局作用域下独立调用函数,this指向window

    function test() {
      console.log(this===window);  //true
    }
    test();
复制代码

2、隐式绑定规则

理解:谁调用就指向谁

1.对象内调用方法

    let obj = {
      name: 'obj',
      foo: function () {
        console.log(this);   //this指向obj
      }
    }
    obj.foo()
复制代码

2.修改一下:

    let obj = {
      name: 'obj',
      foo: function () {
        console.log(this);    //obj
        function test() {
          console.log(this);  //window  为什么?  因为test独立调用
        }
        test()
      }
    }
    obj.foo()
复制代码

3.隐式丢失:

    let obj = {
      name: 'obj',
      foo: function () {
        console.log(this);  //window   为什么不是obj?  bar拿到obj.foo的引用,然后在全局下独立调用
      }
    }
    let bar = obj.foo
    bar()
复制代码

4.函数作为参数:

    function foo() {
      console.log(this);  //window  obj.foo在bar函数内独立调用  
    }
    function bar(fn) {
      fn()
    }
    let obj = {
      name: 'obj',
      foo: foo
    }
    bar(obj.foo)
复制代码

4.1函数作为参数时,参数函数叫做子函数,外面的函数叫父函数,子函数也叫回调函数,像这样的函数有很多,

比如forEach 、setimeout,这些函数里的参数函数也叫内置参数

记住:父函数有能力决定子函数this的指向,例如forEach里第一个参数是一个函数,第二个参数就是this绑定的对象,不写默认绑定window

3、显式绑定

call、apply、bind bind返回一个新函数,新函数指向绑定的对象,旧函数不会

4、new绑定

this指向函数实例化之后的对象

5、绑定规则优先级:

new绑定 > 显式绑定 > 隐式绑定 > 默认绑定

四、箭头函数this指向问题:

1.箭头函数没有自己的this指向,它的this指向上一级作用域的this

1.1之前,我们想让内部函数的this指向外部函数的this,我们只能这样:

    var a = 0
    function foo() {
      let that = this   //指向obj
      console.log(this);
      function test() {
      console.log(that)  //指向obj
       
      }
      test()
    }
    let obj = {
      a: 1,
      foo: foo
    }
    obj.foo()
复制代码

1.2或者使用bind/call/apply显式绑定外部函数的this:

    var a = 0
    function foo() {
      console.log(this);  //指向obj
      function test() {
        console.log(this);
      }
      test.call(obj)
    }
    let obj = {
      a: 1,
      foo: foo
    }
    obj.foo()
复制代码

2.箭头函数this指向不遵循上述的四种规则:

2.1独立调用对箭头函数无效:

    var a = 0
    function foo() {
      let test = () => {
        console.log(this)
      }
      return test
    }
    let obj = { a: 1, foo: foo }
    obj.foo()()
   //  obj.foo()返回test  obj.foo()()调用test  而且是独立调用  但是this还是指向obj
复制代码

隐式绑定对箭头函数无效:

    let a = 0
    let obj1 = {
      a: 1,
      foo: () => {
        console.log(this);
      }
    }
    obj1.foo() //指向window
复制代码

2.3显式绑定对箭头函数无效:

    var a = 0
    function foo() {
      let test = () => {
        console.log(this)
      }
      return test
    }
    let obj1 = {
      a: 1,
      foo: foo
    }
    let obj2 = {
      a: 2,
      foo: foo
    }
    obj1.foo().call(obj2)
​
     //obj1.foo()返回test   obj1.foo.call(obj2)把test的指向绑定到obj2上,无效,this依然指向obj1
复制代码
分类:
前端