JS_01_this指向总结

一、背景

在大多数情况下, this都是出现在函数中。在全局作用域下,this在不同的环境有不同的指向:

  • 浏览器: window(globalObject)
  • Node环境: {}

这里主要讲的是在浏览器中的this指向:

​ 结论:在js中,this指向什么, 跟函数所处的位置是没有关系的,跟函数被调用的方式是有关系

二、this绑定的四种方式

this的四个绑定法则:默认绑定、隐式绑定、显示绑定、new绑定

  1. 默认绑定:独立函数调用,只要是独立的调用方式,this指向都是window

    1. 案例一:

      function foo() {
        console.log(this)
      }
      foo() //window
      

      案例二:

      function foo1() {
        console.log(this)
      }
      
      function foo2() {
        console.log(this)
        foo1() //单独调用,
      }
      
      function foo3() {
        console.log(this)
        foo2() //单独调用,
      }
      
      foo3()//单独调用,
      

      案例三:

      var obj = {
        name: "why",
        foo: function() {
          console.log(this)
        }
      }
      var bar = obj.foo
      bar() //单独调用 window
      

      案例四:

      function foo() {
        function bar() {
          console.log(this)
        }
        return bar
      }
      
      var fn = foo()
      fn() // window
      
  2. 隐式绑定:通过一个对象的属性来调用的方式,例如 object.fn(), object对象会被js引擎绑定到fn函数的中this里面

    案例一:

    var obj = {
      name: "why",
      foo: foo
    }
    obj.foo() // obj对象
    

    案例二:

    var obj = {
      name: "why",
      eating: function() {
        console.log(this.name + "在吃东西")
      },
      running: function() {
        console.log(obj.name + "在跑步")
      }
    }
    
    obj.eating()  //指向obj
    obj.running()//指向obj
    
    var fn = obj.eating
    fn() //指向window,为绑定一的默认方式
    

    案例三:

    var obj1 = {
      name: "obj1",
      foo: function() {
        console.log(this)
      }
    }
    
    var obj2 = {
      name: "obj2",
      bar: obj1.foo
    }
    obj2.bar() // obj2
    
    
  3. 显示绑定:call,apply和bind的绑定,call和apply在执行函数时,是可以明确的绑定this, 这个绑定规则称之为显示绑定

    //call/apply是可以指定this的绑定对象
    foo.call(obj) //obj
    foo.apply(obj) //obj
    foo.apply("aaaa") //aaa
    // call和apply的区别是传参方式的不同
    function sum(num1, num2, num3) {
      console.log(num1 + num2 + num3, this)
    }
    
    sum.call("call", 20, 30, 40)
    sum.apply("apply", [20, 30, 40])
    
    //bind的绑定:默认绑定和显示绑定bind冲突: 优先级(显示绑定)
    var newFoo = foo.bind("aaa")
    newFoo() //aaa
    newFoo()//aaa
    newFoo()//aaa
    
  4. new绑定: 我们通过一个new关键字调用一个函数时(构造器), 这个时候this是在调用这个构造器时创建出来的对象,this = 创建出来的对象, 这个绑定过程就是new 绑定(都指向new的赋值的参数对象)

    function Person(name, age) {
      this.name = name
      this.age = age
    }
    
    var p1 = new Person("why", 18)
    console.log(p1.name, p1.age)
    
    var p2 = new Person("kobe", 30)
    console.log(p2.name, p2.age)
    

三、一些函数的绑定

//1.setTimeout 指向window
setTimeout(function() {
   console.log(this) // window
}, 2000)
// 2. 点击监听
const boxDiv = document.querySelector('.box')
boxDiv.onclick = function() {
  console.log(this)  // boxDiv
}

boxDiv.addEventListener('click', function() {
  console.log(this)  //window
})
// 3..数组.forEach/map/filter/find,如果没有传入参数,是指向window
var names = ["abc", "cba", "nba"]
names.forEach(function(item) {
  console.log(item, this)  // window
})
names.map(function(item) {
  console.log(item, this)  //传入了cba参数,绑定cba
}, "cba")

四、四个绑定的优先级

总:new > 显示 > 隐式 > 默认

  1. 默认显示的优先级最低

  2. 显示的优先级高于隐式优先级

    function foo() {
      console.log(this)
    }
    
    var obj = {
      name: "obj",
      foo: foo.bind("aaa")
    }
    
    obj.foo()  // aaa
    var bar = obj.foo
    bar() //aaa
    
  3. new的优先级高于显示(new不能和apply,call一起使用)

    var obj = {
      name: "obj",
      foo: function() {
        console.log(this)
      }
    }
    
    // new的优先级高于隐式绑定
    var f = new obj.foo() // foo{}
    
    //案例二: new的优先级高于bind
    function foo() {
      console.log(this)
    }
    
    var bar = foo.bind("aaa")
    var obj1 = new bar() //foo{}
    

五、特殊的绑定

  1. 忽略显示绑定:

    function foo() {
      console.log(this)
    }
    
    foo.apply("abc") //abc
    foo.apply({}) //{}
    
    // apply/call/bind: 当传入null/undefined时, 自动将this绑定成全局对象
    foo.apply(null) //window
    foo.apply(undefined)//window
    
  2. 箭头函数

    1. 特点:箭头函数的this指向是上一箭头函数的上一级的对象

      var foo = () => {
        console.log(this) //这个箭头函数的上一级是 window
      }
      
      foo()// window
      var obj = {foo: foo}
      obj.foo()      // window
      foo.call("abc")// window
      
      
    2. 应用场景案例:

      var obj = {
        data: [],
        getData: function() {
          // 发送网络请求, 将结果放到上面data属性中
          // 在箭头函数之前的解决方案
          // var _this = this  //this指向obj
          // setTimeout(function() {
          //   var result = ["abc", "cba", "nba"]
          //   _this.data = result //这里this的话指向window
          // }, 2000);
          // 箭头函数之后
          setTimeout(() => {
            var result = ["abc", "cba", "nba"]
            this.data = result  //这里的上一级指向obj
          }, 2000);
        }
      }
      
      obj.getData()
      
posted @ 2022-02-27 14:41  LL幻  阅读(30)  评论(0)    收藏  举报