JavaScript 中的 this 指向和修改 this 指向的常用方法 - 个人总结版

前言

JavaScript 中的 this 指向大致可以分为两大部分,即 作为独立函数调用作为对象方法调用

注意:箭头函数中没有 this,也就是箭头函数中的 this 是引用自外层作用域中的 this。

JavaScript 中的 this 指向

参考链接:this - JavaScript | MDN (mozilla.org)

JavaScript 中的常见的 this 指向一般分为如下两大类:

第一大类:作为独立函数调用(隐式绑定 this)

不是通过 对象.(对象方法)的方式来引用的函数中的 this 指向的是 globalThis。

注意:在 严格模式 下,独立函数中的 this 指向为 undefined

常见的四种表现形式如下:

// 表现形式一:直接定义为一个独立函数
function foo() {
  console.log(this === globalThis)
}
foo() // true

const obj = {
  jump() {
    console.log(this === globalThis)
  },
}
// 表现形式二:赋值为一个纯 JavaScript 对象成员方法
const bar1 = obj.jump
bar1() // true

class Person {
  run() {
    console.log(this)
  }
  static staticMethod() {
    console.log(this)
  }
}
const p = new Person()

// 表现形式三:赋值为一个类实例对象方法
const bar2 = p.run
bar2()
// undefined

// 表现形式四:赋值为一个类静态方法
const bar3 = Person.staticMethod
bar3()
// undefined

需要注意一下表现形式三(赋值为类实例方法)和表现形式四(赋值为类静态方法),函数内部 this 指向的不是全局对象 globalThis,而是 undefined。

原因:class 是函数原型链继承的语法糖形式,底层最终会被编译成原型链继承,默认启用严格模式,而严格模式下的独立函数中的 this 指向 undefined。

globalThis 介绍 - MDN 链接:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/globalThis

globalThis 提供了一个标准的方式来获取不同环境下的全局 this 对象(也就是全局对象自身)。

  1. 在浏览器环境下,globalThis 指向的是全局的 window 对象。

  2. 在 Node.js 环境下,即通过 node 等命令运行 JavaScript 脚本文件时,globalThis 指向的是全局的 global 对象。

其他环境以此类推,globalThis 都是指向全局中的 this(也就是全局对象自身)。

第二大类:作为对象方法调用(显式绑定 this)

作为对象方法,就是通过 对象.xxx() 的方式来调用的函数,其 this 指向引用其的对象

对象方法的三种常见表现形式如下:

  • 表现形式一:作为一个纯 JavaScript 对象的方法时,其 this 指向为该对象本身
const obj = {
  run() {
    return this
  }
}
const thisObj = obj.run()
console.log(thisObj === obj) // true
  • 表现形式二:作为类实例方法时,其 this 指向类实例对象

    知识补给:class 类是 js 原型链继承的语法糖形式,类实例方法最终会被编译成一个与类同名的函数的原型对象 prototype 上的一个共享方法。

    参考链接:继承与原型链 - JavaScript | MDN (mozilla.org)

    class Person {
      run() {
        return this
      }
    }
    const p = new Person()
    const thisObj = p.run()
    console.log(thisObj === p) // true
    // p 是 Person 类实例对象,所以根据继承原型链可知 p.__proto__.constructor === Person
    console.log(p.__proto__.constructor === Person) // true
    console.log(thisObj instanceof Person) // true
    console.log(thisObj instanceof p.__proto__.constructor) // true
    
  • 表现形式三:作为类静态方法时,其 this 指向类本身

    知识补给:class 类是 js 原型链继承的语法糖形式,类静态实例方法最终会被编译成一个与类同名的函数对象上的一个成员方法。

    class Person {
      static run() {
        return this
      }
    }
    const thisObj = Person.run()
    console.log(thisObj === Person) // true
    

简单理解就是:通过谁来调用该方法,那么该方法中的 this 就指向谁。

修改 this 指向

可以使用 Function.prototype.call()Function.prototype.apply()Reflect.apply() 方法显式设置 this 的值。使用 Function.prototype.bind(),你可以创建一个新的函数,无论函数如何被调用,其 this 的值都不会改变。当使用这些方法时,无论函数是处于严格模式还是非严格模式下,上述 this 替换规则仍然适用。

常用的几个修改函数中的 this 指向的方法就是 apply、call、和 bind

apply、call、和 bind 三者的相同点:都是通过参数1来指定函数中的 this 指向。

apply、call、bind 的不同点

  1. apply 和 call 是修改 this 指向的同时调用该函数,而 bind 是返回一个绑定了指定的 this 后的新函数。

  2. apply 是通过向参数2传递一个 参数数组 的方式来向目标函数传递实参,而 call 和 bind 则是通过一个 参数列表 的方式传递实参。

    知识补给:参数列表就是一个以 , 分隔参数的表达式,形如:参数1, 参数2, ..., 参数n

function foo(name, age) {
  console.log(name, age, this.hobbies)
  return this
}

const thisObj = foo()
console.log(thisObj === globalThis) // true

const person1 = { hobbies: ['唱'] }
const person2 = { hobbies: ['跳'] }
const person3 = { hobbies: ['rap'] }

foo.apply(person1, ['zhangsan', 18])
// zhangsan 18 [ '唱' ]

foo.call(person2, 'zhangsan', 18)
// zhangsan 18 [ '跳' ]

const newFoo = foo.bind(person3, 'zhangsan', 18)
newFoo()
// zhangsan 18 [ 'rap' ]
  • 38
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

coderyzj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值