不懂就问 GPT:class 组件中的 this 问题怎么来的?

最近在重新学习 React hooks,在玩转 React Hooks这本小册中读到下面这段,于是温故了一下 class 中 this 问题的产生:

之所以 Class 组件需要 bind 的根本原因是在 React 的事件机制中,dispatchEvent 调用的 invokeGuardedCallback 是直接使用的 func,并没有指定调用的组件,所以在 Class 组件中的方法都需要手动绑定 this。

而箭头函数本身并不会创建自己的 this,它会继承上层的 this,所以不需要进行绑定,this 本身就是指向的组件。


maidangzhu: 介绍一下 invokeGuardedCallback 和 class 中 this 问题的关系


Raycast AI: invokeGuardedCallback 是 React 的一个内部方法,它被用来捕获和处理在调用函数时产生的错误。在 React 的 event system 中,它用于确保异常被抛出到合适的地方,并且运行时的错误不会导致整个 React 事件系统的崩溃。

在 JavaScript 的 class 中,this 的值在默认情况下并不会自动绑定到类的方法中。这意味着如果你以回调函数的形式传递类的方法,该方法中的 this 就会失效。例如,考虑以下 React 组件:

scala 复制代码
class MyComponent extends React.Component {
  doSomething() {
    console.log(this.props);
  }

  render() {
    return <button onClick={this.doSomething}>Click me</button>;
  }
}

在这个例子中,如果你点击按钮,就会在控制台中看到"TypeError: Cannot read property 'props' of undefined",这是因为 doSomething 方法作为回调函数传递给 onClick,在 doSomething 内部,this 不再指向 MyComponent 实例。

这是经常让新手困扰的问题,常见的解决办法是在构造函数中绑定 this,或使用类属性语法(arrow function):

scala 复制代码
class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.doSomething = this.doSomething.bind(this);
  }

  // 或者
  doSomething = () => {
    console.log(this.props);
  }

  render() {
    return <button onClick={this.doSomething}>Click me</button>;
  }
}

invokeGuardedCallback 在 React 事件系统中处理事件回调时,也会需要应对这样的 this 绑定问题。对于由类组件生成的事件处理器,由于 JavaScript 的这种 this 的特性,React 内部处理时需要确保 this 的正确指向,这就是 invokeGuardedCallback 和 class 中 this 问题的关系。


maidangzhu: invokeGuardedCallback 和 dispatchEvent 的关系


Raycast AI: invokeGuardedCallbackdispatchEvent 都属于事件处理的一部分,它们在 React 中被用来处理用户交互和生命周期事件的异常。这相当于在执行回调过程中构建了一个"安全区"。

  1. invokeGuardedCallback :这是 React 的一个内部方法。主要是调用给定的函数,并捕获并返回由函数抛出的任何错误。这就像创建一个安全的沙箱环境,在该环境中执行我们的代码,如果代码出错,那么错误会被 catch,而不会影响到其他代码。使用 invokeGuardedCallback 执行事件处理程序有利于错误追踪,并防止错误在用户代码中可能引起的连锁反应。
  2. dispatchEvent :这是一个 DOM 方法,用于触发特定事件。在 React 中,由于 React 维护了自己的事件系统,实际上 React 创建和维护了 top-level 的 event listeners,来处理用户的交互。当事件触发时,React 内部实际上会使用一种合成事件(SyntheticEvent)来模拟 DOM 事件。这个过程最后一步,React 通常会调用 dispatchEvent,在这之前会使用 invokeGuardedCallback 方法执行用户提供的事件处理器,确保即使处理器内部出错也不会影响到全局。

这两个函数一起,无论是在 React 自己的事件系统中,还是在 DOM 事件系统中,创建了一个更安全的环境以执行回调,且当错误发生时,它们不会中断整个应用程序的执行。


maidangzhu: 那这和在 class 组件中的 this 获取不到又有什么关系呢


Raycast AI: 在 JavaScript 类(class)中,方法默认不会自动绑定 this,这也就意味着当你将类的方法作为回调函数使用时,this 可能变得不可用。这在 React 类组件中处理事件时通常是一个问题,因为用户在为像 onClickonChange 这样的事件处理器提供函数时,经常会需要在方法中访问组件的 propsstate 或其他方法。

当使用 invokeGuardedCallback 方法调用事件处理器时,React 需要在执行函数之前正确地设置 this 。因此,如果你写的是类组件,且在事件处理器中使用了 this(如 this.setStatethis.props.onClick),React 就需要确保 this 指向你的组件实例。

在函数式组件和类组件中,事件处理器的 this 行为是不同的。在类组件中,你通常需要将回调函数绑定到组件实例上,以便在回调中使用 this。这个绑定过程通常在构造函数中进行:

scala 复制代码
class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    console.log(this.props);
  }

  render() {
    return <button onClick={this.handleClick}>Click me</button>;
  }
}

所以虽然 invokeGuardedCallback 和这个 this 获取问题是两个相互独立的问题,它们在实际的事件处理场景下可能同时参与其中,React 也为此提供了对应的解决方案。


maidangzhu: 为什么在 JavaScript 类(class)中,方法默认不会自动绑定 this


Raycast AI: 在 JavaScript 中,this 的值是由调用上下文决定的,而不是由在哪里定义函数决定的。因此,当你从对象中提取一个方法并调用它时,它的 this 通常指向 undefined,而不是该对象。

这也适用于 JavaScript 的 class 中定义的方法。类中的方法默认情况下不会将 this 绑定到实例。这就是为什么当你直接调用一个类的方法或将其作为回调函数(例如事件处理程序)提供给另一个函数时,必须手动绑定 this 或使用箭头函数。

看下面的代码示例:

ini 复制代码
class Test {
  prop = "Test class";

  unboundFunction() {
    console.log(this.prop);
  }
}

let test = new Test();

// 提取并调用函数,'this' 是 'undefined'
let func = test.unboundFunction;
func(); // => TypeError: Cannot read property 'prop' of undefined

在这个例子中,当你尝试调用 unboundFunction,JavaScript 试图访问 undefinedprop 属性,导致 TypeError。

反之,如果我们将方法与类的实例绑定,this 将能正确访问:

javascript 复制代码
class Test {
  prop = "Test class";

  constructor() {
    this.boundFunction = this.boundFunction.bind(this);
  }

  boundFunction() {
    console.log(this.prop);
  }
}

let test = new Test();

// 提取并调用函数,'this' 现在指向 'test'
let func = test.boundFunction;
func();  // => 输出: 'Test class'

这有一部分原因是 JavaScript 相比其他面向对象语言如 Java 或 C++ 在 this 中的差异。在那些语言中,类中的方法默认的 this 指向对象实例,而 JavaScript 不是这样的。

相关推荐
开心工作室_kaic3 分钟前
ssm068海鲜自助餐厅系统+vue(论文+源码)_kaic
前端·javascript·vue.js
有梦想的刺儿22 分钟前
webWorker基本用法
前端·javascript·vue.js
清灵xmf1 小时前
TypeScript 类型进阶指南
javascript·typescript·泛型·t·infer
小白学大数据1 小时前
JavaScript重定向对网络爬虫的影响及处理
开发语言·javascript·数据库·爬虫
qq_390161771 小时前
防抖函数--应用场景及示例
前端·javascript
334554322 小时前
element动态表头合并表格
开发语言·javascript·ecmascript
John.liu_Test2 小时前
js下载excel示例demo
前端·javascript·excel
PleaSure乐事2 小时前
【React.js】AntDesignPro左侧菜单栏栏目名称不显示的解决方案
前端·javascript·react.js·前端框架·webstorm·antdesignpro
哟哟耶耶2 小时前
js-将JavaScript对象或值转换为JSON字符串 JSON.stringify(this.SelectDataListCourse)
前端·javascript·json
getaxiosluo2 小时前
react jsx基本语法,脚手架,父子传参,refs等详解
前端·vue.js·react.js·前端框架·hook·jsx