JavaScript -- this 关键字

面向对象语言中 this 表示当前对象的一个引用。但在 JavaScript 中 this 不是固定不变的,它会随着执行环境的改变而改变。

每一个函数内部都有一个关键字this ,并且this 可供直接调用

函数内部的 this 只和函数的调用方式有关系,和函数的定义方式没有关系

  • 全局定义的函数直接调用,this => window

    function fn() {
      console.log(this);
    }
    fn();
    // 此时 this 指向 window
    
  • 对象内部的方法调用,this => 调用者

    const obj = {
      fn: function () {
        console.log(this);
      }
    }
    obj.fn();
    // 此时 this 指向 obj
    
  • 定时器的处理函数,this => window

    setTimeout(function () {
      console.log(this)
    }, 0)
    // 此时定时器处理函数里面的 this 指向 window
    
  • 事件处理函数,this => 事件源

    div.onclick = function () {
      console.log(this)
    }
    // 当你点击 div 的时候,this 指向 div
    
  • 自调用函数,this => window

    (function () {
      console.log(this)
    })()
    // 此时 this 指向 window
    
  • 箭头函数,箭头函数内部没有 this,箭头函数的 this上下文的 this

    // 在箭头函数定义的位置往上查找,这一行是可以打印出 this 的
    // 因为这里的 this 是 window
    // 所以箭头函数内部的 this 就是 window
    const obj = {
      fn: function () {
        console.log(this)
      },
      // 这个位置是箭头函数的上一行,但是不能打印出 this
      fun: () => {
        // 箭头函数内部的 this 是书写箭头函数的上一行一个可以打印出 this 的位置
        console.log(this)
      }
    }
    
    obj.fn()
    obj.fun()
    

显式函数绑定

在 JavaScript 中函数也是对象,对象则有方法,applycall 就是函数对象的方法。这两个方法异常强大,他们允许切换函数执行的上下文环境(context),即 this 绑定的对象。

  • apply

    • apply 方法是附加在函数调用后面使用,可以忽略函数本身的 this 指向
    • 语法: 函数名.apply(要改变的 this 指向,[要给函数传递的参数1, 要给函数传递的参数2, ...])
    const obj = { name: 'Jack' };
    function fn(a, b) {
      console.log(this);
      console.log(a);
      console.log(b);
    }
    fn(1, 2); // this => window
    fn.call(obj, [1, 2]); // this => obj
    
    • 使用 apply :
      • 会立即执行函数
      • 第一个参数是你要改变的函数内部的 this 指向
      • 第二个参数是一个 数组,数组里面的每一项依次是向函数传递的参数
  • call

    • call 方法是附加在函数调用后面使用,可以忽略函数本身的 this 指向
    • 语法: 函数名.call(要改变的 this 指向,要给函数传递的参数1,要给函数传递的参数2, ...)
    const obj = { name: 'Jack' };
    function fn(a, b) {
      console.log(this);
      console.log(a);
      console.log(b);
    }
    fn(1, 2); // this => window
    fn.call(obj, 1, 2); // this => obj
    
    • 使用 call:
      • 会立即执行函数
      • 第一个参数是你要改变的函数内部的 this 指向
      • 第二个参数开始,依次是向函数传递参数
  • bind

    • bind 方法是附加在函数调用后面使用,可以忽略函数本身的 this 指向
    • call / apply 有一些不一样,它不会立即执行函数,而是返回一个已经改变了 this 指向的函数
    • 语法: const newFn = 函数名.bind(要改变的 this 指向); newFn(传递参数)
    const obj = { name: 'Jack' };
    function fn(a, b) {
      console.log(this);
      console.log(a);
      console.log(b);
    }
    fn(1, 2);
    const newFn = fn.bind(obj); // 改变了 this 指向
    newFn(1, 2); // 执行结果一致,但是 this => obj
    
    const foo = fn.bind(obj, 1); //柯里化,预设置参数
    foo(2); // 输出 1,2
    

总结

  • this 是作用域内部使用的关键字
  • this 指向不看函数定义,只和调用方式有关
    • 全局调用 fn() this => window
    • 对象调用 obj. fn() this => obj
    • 定时器函数 this => window
    • 事件处理函数 this => 事件源
    • 自执行函数 this => window
    • 构造函数 this => 当前实例
    • 箭头函数 没有 this ,它的 this 是上下文,即外部作用域的 this