关于JavaScript中this的四种绑定方式

66 阅读3分钟

一、this的默认绑定

什么情况下使用默认绑定呢?独立函数调用

  • 独立函数的调用我们可以理解为函数没有被绑定到某个对象上进行调用;
  • 默认绑定this指向的是window
  • 严格模式下,独立调用的函数中this指向的是undefined

案例如下:

//案例一
    function a() {
    console.log(this); // window
    }
    a();
//案例二
    function test1() { 
        console.log(this); // window 
        test2(); 
    } 
    function test2() { 
        console.log(this); // window 
        test3(); 
    } 
    function test3() { 
        console.log(this); // window 
    } 
    test1();
    //案例三
    function foo (func) {
        func();
    }
    
    var obj = {
        name: "ken",
        bar: function () {
            console.log(this)
        }
    }
    
    foo(obj.bar);

二、隐式绑定

隐式绑定比较常见的调用方式是通过某个对象调用的

  • 也就是它的调用位置是处于某个对象里面,是某个对象发起的函数调用,此时this指向这个对象。

案例如下:

    //案例一
    function foo() {
        console.log(this); // obj
    }
    
    var obj = {
        name: "ken",
        foo: foo
    };
    
    obj.foo();
    //案例二
    function foo() {
        console.log(this); // obj1
    };

    var obj1 = {
        name: "obj1",
        foo: foo
    };

    var obj2 = {
        name: "obj2",
        obj1: obj1
    };

    obj2.obj1.foo();

三、显性绑定

  • 显性绑定指的是通过call、apply或者bind绑定
  • call、apply、bind三者的区别:
    • call 从第二个参数开始所有的参数都是原函数的参数(第一个参数是this指向的对象)。

          //案例
          function foo(name, age, height) {
              console.log(this, name, age, height);
              // String {'abc'} 'ken' 18 '165cm'
          }
          foo.call("abc", "ken", 25, "165cm");
      
    • apply 只接受两个参数,且第二个参数必须是数组,这个数组代表原函数的参数列表,第一个参数也是this指向的对象。

          //案例
          function foo(name, age, height) {
              console.log(this, name, age, height); // String {'abc'} 'ken' 18 '165cm'
          }
      
          foo.apply("abc", ["ken", 18, '165cm']);
      
    • bind bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数(bind会返回一个新的绑定函数)的参数,供调用时使用。

          //案例
          function bfoo () {
              console.log(this.a);
          }
      
          let bobj = { a: 10 };
          bfoo = bfoo.bind(bobj);
          
          bfoo();    // 10
      
    • bind 和 call、apply 的区别:

      1. 通过apply和call方法绑定this, 不能总是绑定到一个对象上, 每次调用时都需要绑定对应的对象。而bind 绑定后,会锁死this。
      2. bind 是返回一个新的绑定函数,call、apply不会返回新函数。

四、new绑定

JavaScript中的函数可以当作一个类的构造函数来使用,也就是使用new关键字,使用new关键字来调用函数,会执行如下操作:

  1. 创建一个新的对象
  2. 这个新对象会被执行prototype连接;
  3. 构造函数内部的this会指向创建出来的新对象。(此时this完成绑定)
  4. 执行构造函数里面的代码(函数体代码)
  5. 如果函数没有明确返回其他对象,那么表达式返回这个创建出来的新对象。

例子如下:

    //案例
    function Person(name){
        console.log(this); // Person {},没有添加其他属性或方法的情况下,默认返回一个空对象。
        this.name = name; // 接受参数,并返回带有相应属性的实例对象。
    }

    var p = new Person("ken"); // 传参数
    console.log(p); // Person {name: "ken"}

五、内置函数的this

  • 定时器的this指向window, 事件函数中的this指向事件调用者, forEach中的this默认指向window,特殊:箭头函数没有this。

六、各种绑定规则的优先级

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

七、总结:

  • 如果函数被 new 修饰,this 绑定的是新创建的对象,例如 var bar = new foo();函数 foo 中的 this 就是一个叫 foo 新创建的对象,然后将这个对象赋给 bar,这样的绑定叫做 new 绑定。
  • 如果函数是使用 call,apply,bind 来调用的,this 绑定的 是 call,apply,bind 中的第一个参数,例如 foo.call( obj ),foo 中的 this 就是 obj,这样的绑定方式叫 显式绑定。
  • 如果函数是在某个上下文下被调用,this 绑定的就是那个上下文对象,例如 var obj = { foo: foo }; obj.foo; foo 中的 this 就是 obj,这样的绑定叫 隐性绑定。
  • 如果都不是,即使用默认绑定。一般 this 绑定的是 this,严格模式下绑定到 undefined。