Skip to content

this

前言

this关键字是当前执行上下文的一个对象,在面向对象类的语言中表示当前实例对象的一个引用

但在JavaScript中,this的指向可不是一成不变的,它很灵活,灵活到会根据 当前执行环境 的变化而变化

this 指向绑定规则

在前言,我们说过this很灵活,它的绑定与定义的环境位置无关,而是跟绑定与调用环境有关,this是在运行时确定指向的

常见的四种绑定方式

  • 独立调用,指向globalThis
  • 隐式绑定,函数被对象引用并调用
  • 显式调用,使用applycallbind等方法改变this的指向
  • new关键字绑定

globalThis

以前从不同的 JavaScript 环境中获取全局对象需要不同的语句,获取全局属性的繁琐程度极大增加。

globalThis  提供了一个标准的方式来获取不同环境下的全局  this  对象,无论你在哪个环境,它会确保可以在有无窗口的各种环境下正常工作,你只需要记住,全局作用域中的  this  就是  globalThis

独立调用

独立调用表示没有对象.语法的方式调用的独立函数调用执行方式,例如fn(),这种方式的this指向的是当前环境的globalThis

js
// 1.独立调用函数,执行输出this为window
function fn() {
  console.log(this)
}

fn()

// 2.在对象中定义函数,但是执行时独立调用,依然指向全局
var obj = {
  name: 'test this',
  fn: function () {
    console.log(this)
  }
}

var objFn = obj.fn
objFn()

// 3.在函数内部,存在独立调用,依然指向全局
function bar(callback) {
  callback()
}

bar(fn)

// 4.严格模式下,独立调用的this返回undefined
function strict() {
  'use strict'
  console.log(this)
}

strict()

隐式绑定

所谓的隐式绑定,就是通过对象.语法调用的函数,当前调用的函数的this会绑定到这个对象上面

js
var obj = {
  name: 'test this',
  fn: function () {
    console.log(this)
  }
}

// 1.对象点语法,函数执行输出this为当前的obj对象
obj.fn()

// 2.传入函数中,以对象点语法调用,this依然指向这个对象
function bar(obj) {
  obj.fn()
}

bar(obj)

显式绑定

使用applycallbind等方法改变this的指向,这三个函数原型的方法都会改变this的指向,例如 fn.apply() 调用它们,就可以显式改变this的指向,它们大致功能都是改变this指向,只在使用上有些许差别

它们在传递第一个参数——this指向时,都有一个共同的特点,如果第一个实参为非引用数据类型,那么this会绑定到该实参的 包装类 上,如果实参没有包装类,那么当前次的显式绑定会变成独立调用,也就是指向全局this

  • apply:执行函数,传递两个参数,第一个参数是需要改变绑定的this,第二个参数是函数调用的实参列表,以数组方式传递
  • call:执行函数,传递两个参数,第一个参数是需要改变绑定的this,剩下的参数是函数调用的实参列表,以剩余参数传递
  • bind:执行函数,传递两个参数,第一个参数是需要改变绑定的this,剩下的参数是函数调用的实参列表,以剩余参数传递,并且该函数会范湖一个新的函数,新的函数就算是独立调用,后续也不会改变它的this指向
js
var obj = {
  name: '张三',
  age: 18
}

function foo(...args) {
  console.log(this)
}

// 1.apply测试传入第一个参数类型,call、bind同理
foo.apply('abc') // String {'abc'}
foo.apply(123) // Number {123}
foo.apply(true) // Boolean {true}
foo.apply(null) // window
foo.apply(undefined) // window
foo.apply(123n) // BigInt {123n}
foo.apply(Symbol('symbol')) // Symbol {Symbol(symbol), description: 'symbol'}

// 2.apply,执行输出 this => obj
foo.apply(obj, ['abc', 123])

// 3.call,执行输出 this => obj
foo.call(obj, 'abc', 123)

// 4.bind,执行输出 this => obj,并返回函数
var newFn = foo.bind(obj, 'abc', 123, true)
newFn()

new 绑定

new 关键字 能帮我们通过一个“构造函数”实例化一个对象,通过newthis绑定到实例对象上

js
function Foo() {
  this.name = 'Foo 构造函数'
  console.log(this)
}

// 1.new关键字实例对象,this指向了foo实例对象
var foo = new Foo()

实例对象

由构造函数创建的具体对象。当使用 new 关键字调用构造函数时,它会返回一个新的对象(实例对象),该对象继承了构造函数的属性和方法。

绑定规则的优先级

上述的四个绑定规则,它们之间也是存在优先级,下列的注意事项掌握后,优先级也就不成问题了

  • 独立调用,优先级最低,会被任意一种绑定规则覆盖
  • 隐式绑定,它的优先级仅在独立调用之后,显式绑定之前
  • 显式绑定apply/call/bind之间也存在优先级问题,bind的优先级高于apply/callapplycall是同级,后面的绑定会覆盖前面的
  • new绑定,优先级最高,但是new会和apply/call互斥

绑定规则的优先级总结下来就是:

  • newapply/call存在互斥,不能一同使用
  • new绑定会覆盖所有的绑定 > bind > apply/call > 隐式绑定 > 独立调用

总结

  1. this的绑定是根据当前函数的执行上下文决定的,它会在函数运行时确定this指向
  2. this的四种绑定规则
    • 独立调用
    • 隐式绑定
    • 显式绑定
    • new绑定
  3. 绑定规则的优先级
    • newapply/call存在互斥,不能一同使用
    • new绑定 > bind > apply/call > 隐式绑定 > 独立调用

如有转载或 CV 的请标注本站原文地址