【问题标题】:why do you need to bind a function in a constructor为什么需要在构造函数中绑定函数
【发布时间】:2021-06-17 11:12:04
【问题描述】:

我有一个与此代码相关的问题:https://github.com/reactjs/redux/blob/master/examples/async/containers/App.js

具体来说:

  constructor(props) {
    super(props)
    this.handleChange = this.handleChange.bind(this)
    this.handleRefreshClick = this.handleRefreshClick.bind(this)
  }

我猜这是一个两部分的问题。

  1. 为什么我需要将句柄更改设置为this.handleChange = 类的实例,我不能只使用静态函数来处理句柄更改并在onClick={handleRefreshClick}> 类中直接调用它吗?
  2. 我不知道这里发生了什么:this.handleRefreshClick.bind(this)

谢谢

【问题讨论】:

  • 不完全是,我不太了解一个类的上下文,尤其是数字 2
  • 它不会改变bind 的含义。您使用bind 来维护this 的范围。在 react 的上下文中,这允许您调用诸如 this.setState 之类的东西。

标签: reactjs redux


【解决方案1】:

这里的所有答案都很好,但为了清楚起见:

  1. 我不知道这里发生了什么:this.handleRefreshClick.bind(this)

我认为一个例子最能描述行为上的差异。

// Class where functions are explicitly bound to "this" specific object
var Bindings = class {
  constructor() {
    this.Firstname = "Joe"
    this.Surname = "Blow"
    this.PrettyPrint = this.PrettyPrint.bind(this)
    this.Print = this.Print.bind(this)
  }

  Print(inputStr) {
    console.log(inputStr)
    console.log(this)
  }

  PrettyPrint() {
    this.Print(`${this.Firstname} ${this.Surname}`)
  }
}

// Class where "this" context for each function is implicitly bound to 
//  the object the function is attached to / window / global
//  identical class, except for removing the calls to .bind(this)
var NoBindings = class {
  constructor() {
    this.Firstname = "Joe"
    this.Surname = "Blow"
  }

  Print(inputStr) {
    console.log(inputStr)
    console.log(this)
  }

  PrettyPrint() {
    this.Print(`${this.Firstname} ${this.Surname}`)
  }
}

var bindings = new Bindings()
var noBindings = new NoBindings()

bindings.PrettyPrint() 
// > "Joe Blow"
// > Object { Firstname: "Joe", Surname: "Blow", PrettyPrint: PrettyPrint(), Print: Print() }

noBindings.PrettyPrint() 
// > "Joe Blow"
// > Object { Firstname: "Joe", Surname: "Blow" }

// noBindings has both functions & everything works as we expect, 
// if this is all you're doing, then there's practically little difference,
// but if we separate them from the original "this" context...

var b = { PPrint: bindings.PrettyPrint }
var nb = { PPrint: noBindings.PrettyPrint }

b.PPrint()
// > "Joe Blow"
// > Object { Firstname: "Joe", Surname: "Blow", PrettyPrint: PrettyPrint(), Print: Print() }
// PPrint calls "PrettyPrint" where "this" references the original "bindings" variable
// "bindings" has a function called "Print" which "PrettyPrint" calls

nb.PrettyPrint() 
// > Uncaught TypeError: this.Print is not a function
// PPrint calls "PrettyPrint" where "this" references the new "nb" variable 
// due to different "this" context, "nb" does not have a function called "Print", so it fails

// We can verify this by modifying "bindings" and seeing that it's reflected in "b"
bindings.Surname = "Schmo"
b.PPrint()
// > "Joe Schmo"
// > Object { Firstname: "Joe", Surname: "Schmo", PrettyPrint: PrettyPrint(), Print: Print() }

// We can also add a "Print" method to "nb", and see that it's called by PrettyPrint
nb.Print = function(inputStr) { console.log(inputStr); console.log(this) }
nb.PPrint()
// > undefined undefined
// > Object { PPrint: PrettyPrint(), Print: Print(inputStr) }

// The reason we get "undefined undefined", 
//  is because "nb" doesn't have a Firstname or Surname field.
//  because, again, it's a different "this" context

【讨论】:

    【解决方案2】:

    this 取决于函数的调用方式,而不是创建方式/创建位置。

    当您查看代码时,您会看到两个“this”,为什么?看起来很奇怪,对吧? 问题并不在于它看起来如何。它是关于它是如何被调用的。

    你基本上是在说。嘿,当有人打电话给你时,记住this 表示这个类。不是别的。

    当有人像 x.yourClass().bind(this) 这样称呼您的班级时,您是在说 this 不是 x 而是班级本身(带有道具和状态等)。

    快速注意,即使您直接调用 yourClass() 之类的类,您实际上也是在调用 window.yourClass()在浏览器上,这也是为什么在这种情况下 this是窗口。

    【讨论】:

      【解决方案3】:

      我个人在构造函数中绑定函数,这样它们的引用在每次重新渲染时都不会改变。

      如果您将函数传递给只读子项,而当他们的道具没有改变时您不需要更新,这一点尤其重要。我为此使用 react-addons-pure-render-mixin。

      否则,在每个父级重新渲染时,将发生绑定,将创建新的函数引用并将其传递给子级,这将认为道具已更改。

      【讨论】:

        【解决方案4】:

        这样做的原因是将this 关键字绑定到该对象。正如 Tom 所说,从类中调用函数并不意味着它是在创建该函数的对象的上下文中调用的。

        我认为您可能会感到困惑,因为在 React 示例/教程中,使用 React.createClass() DOES 会自动为您绑定 this。所以你可能想知道为什么 React.createClass() 会这样做,但不使用 ES6 类语法。

        这是因为 React 不想弄乱 ES6 规范(将 this 绑定到其类中的函数不在 ES6 类规范中),但同时,想要为用户提供 ES6 类语法的便利。您可以在下面阅读更多相关信息。

        Github issue

        希望这能解释为什么会发生这种情况。

        【讨论】:

          【解决方案5】:

          以相反的顺序回答...

          1. this.handleRefreshClick.bind(something) 返回一个新函数,其中对this 的引用将引用something。这是一种保存this的当前值的方法,在调用构造函数的过程中,它在作用域内,以便以后调用函数时可以使用。
          1. 如果您的函数不需要访问组件的状态,那么您当然不需要绑定它们。

          支持将这些行添加到构造函数的论点是,新的绑定函数仅在类的每个实例中创建一次。你也可以使用

          onClick={this.handleRefreshClick.bind(this)}
          

          或(ES6):

          onClick={() => this.handleRefreshClick()}
          

          但是这些方法中的任何一个都会在每次重新渲染组件时创建一个新函数。

          【讨论】:

          • 但是做 .bind(this) 一个类的整个想法是它封装了'this'对,那么当一个类的整个实例时,为什么我需要将作用域封装在一个特定的函数中应该封装范围
          • @Saad 不在 JS 中!类真的是just fancy functions;他们不会对this 做任何特别有用的事情。
          • 在 Render 中绑定或使用箭头函数是不好的,因为它会导致在每次渲染时重新分配函数。更好的方法是在构造函数中绑定或在类中使用箭头函数。 medium.freecodecamp.org/…
          • 是的,这就是我的回答中所说的:)
          • @abhinavm93 我的意思是,除非您将this 显式绑定到函数,否则它的值取决于调用它的上下文。 React 使用 render 函数创建带有事件处理程序的 DOM 元素。从处理这些事件的上下文中,不知道这些事件处理程序所属的类,除非您绑定它。
          【解决方案6】:

          这两个函数handleChange和handleRefreshClick作为props传递给其他组件,

          它们绑定到 this 是因为当子组件调用这些函数时,它们总是会在 APP 上下文中执行。

          您可以从类中删除这些函数,但仍然需要绑定它,因为您将更新您的 APP 的某些部分

          【讨论】:

            猜你喜欢
            • 2020-03-10
            • 2018-06-02
            • 1970-01-01
            • 1970-01-01
            • 2021-08-12
            • 2023-04-08
            • 2011-02-25
            相关资源
            最近更新 更多