Javascript:this?

184 阅读4分钟

什么是this

this 是执行上下文中的一个属性(上下文就是指的是一种环境),是指包含它的函数作为方法被调用时所属的对象。听不懂,换种方式解读.

一个函数包含了this,这个函数在哪一个对象里面被调用了,this就是指向这个对象.

  1. 一个函数包含了this.
  2. 对象里面被调用了这个函数.
  3. this指向这个对象

this的规则

  1. 默认绑定

    -this所处的词法作用域在哪里生效了,this就绑定在哪里

    -在严格模式下,全局对象无法进行默认绑定,所以导致this只能绑定在undefined

var a = 5
function fun(){
    var a = 3;
    console.log(this.a)
}
fun() // 5

因为fun函数在全局window上被调用,this指向window.所以此时this.a打印5

  1. 隐式绑定

    -当函数引用有上下文对象时,隐式绑定的规则就会把函数调用中的this绑定到这个上下文对象

        var a = 3
        function fun1(){
            var a = 1;
            console.log(this.a)
        }
        var obj = {
                    a:2,
                    fun1:fun1, //将函数fun1的引用赋值给obj.fun1属性.  
                }
        obj.fun1() // 打印 2 
        fun1() // 打印 3
    

    此时在obj里调用函数的引用,this指向这个对象.

  2. 隐式丢失

    -当隐式绑定的函数丢失了绑定对象,就会应用默认绑定

     var a = 3
      function fun2(){
          var a = 1;
          console.log(this.a)
      }
      var obj = {
                  a:2,
                  fun2:fun2
              }
      var change = obj.fun2;
      change() // 3
    

    这种情况被称为隐式丢失,其实很好理解.将fun2的引用作为值传给obj.fun2,此时在把obj.fun2传给变量change,就相当于直接把fun2的引用赋值给变量change.也就相当于fun2直接在全局下被调用.此时又变回了第一种规则,默认绑定.所以this.a为 3

  3. 显示绑定 用call(),apply(),bind()方法更改this的绑定

  • a.call(obj)
  • b.apply(obj)
  • var bar = foo.bind(obj);bar() -call,apply,bind 可以强行指定一个函数的this的指向
   var a = 3
        function fun3(){
            var a = 1;
            console.log(this.a)
        }
        var obj = {
                    a:2,
                }
    fun3.call(obj);  // 2
    fun3.apply(obj); // 2
    fun3.bind(obj)(); // 2 bind()会有个返回值,而返回值是一个函数 所以还要在后面加一个括号
    fun3() // 3

这三个方法都可以改变this的指向,既然都是可以改变this的指向,那么为什么要三个呢.当然是有一点小小的去别的.

  • call 传入的参数数量不固定,跟 apply 相同的是,第一个参数也是代表函数体内的 this 指向,从第二个参数开始往后,每个参数被依次传入函数。
  • apply 接受两个参数,第一个参数指定了函数体内 this 对象的指向,第二个参数为一个带下标的集合,这个集合可以为数组,也可以为类数组,apply 方法把这个集合中的元素作为参数传递给被调用的函数。
  • bindcall 不同的是bind会有个返回值,这个返回值是一个函数,作用和bind作用的函数功能一样.

显示绑定原理

其实这些方法是巧妙的运用了隐式绑定的规则,通过往对象中添加属性值为改函数的引用来改变this的指向. 这里我们用call举例,怎么手动实现call方法.

    function myCall(obj,...arg){
        if(typeof this !== 'function'){
            console.log('type error')
        }
        obj.fn = this; //向obj对象中添加 添加属性,将调用函数设为对象的方法
        const res = obj.fn(...arg); //将结果保存到一个变量中
        delete obj.fn;//删除对象中的属性
        return res;
    }

这样一个改变this指向的方法就被创建出来了.

this的调用模式

既然了解了this的规则,那么this的调用模式也就能很好理解了.

  • 第一种是函数调用模式,当一个函数不是一个对象的属性时,直接作为函数来调用时,this 指向全局对象。

  • 第二种是方法调用模式,如果一个函数作为一个对象的方法来调用时,this 指向这个对象。

  • 第三种是构造器调用模式,如果一个函数用 new 调用时,函数执行前会新创建一个对象,this 指向这个新创建的对象。

  • 第四种是 applycallbind 调用模式,这三个方法都可以显示的指定调用函数的 this 指向。其中 apply 方法接收两个参数:一个是 this 绑定的对象,一个是参数数组。call 方法接收的参数,第一个是 this 绑定的对象,后面的其余参数是传入函数执行的参数。也就是说,在使用 call() 方法时,传递给函数的参数必须逐个列举出来。bind 方法通过传入一个对象,返回一个 this 绑定了传入对象的新函数。这个函数的 this 指向除了使用 new 时会被改变,其他情况下都不会改变。

总结

希望通过本片文章能够更加清楚的了解this的相关知识,欢迎各位给予建议.