草庐IT

javascript - 带有箭头函数的事件处理程序如何实现上下文绑定(bind)

coder 2025-03-30 原文

我知道 this 绑定(bind)的一般理论(函数调用点很重要,隐式绑定(bind),显式绑定(bind)等...)以及解决 React 中 this 绑定(bind)问题的方法,所以它总是指向我想要的 this 是什么(在构造函数中绑定(bind)、箭头函数等),但我正在努力获得内部机制。

看看这两段代码:

class demo extends React.component {
  goToStore(event) {
    console.log(this)
  }

  render() {
    <button onClick={(e) => this.goToStore(e)}>test</button>
  }
}

对比

class demo extends React.component {
  goToStore(event) {
    console.log(this)
  }

  render() {
    <button onClick={this.goToStore}>test</button>
  }
}

我知道的是:

  • 在两个版本中,我们最终都在 goToStore 方法中成功,因为 render() 方法中的 this 自动绑定(bind)(通过 React)到组件实例
  • 第一个因此成功,
  • 第二个失败,因为es6中的类方法没有绑定(bind)组件实例,从而将方法中的this解析为undefined

据我所知,理论上在第一个版本中会发生以下情况:

  1. 按钮点击处理程序是一个匿名的arrow 函数,因此每当我在其中引用this 时,它都会从环境中获取this (在本例中来自 render())
  2. 然后调用 goToStore 方法,这是一个常规函数。
  3. 因为调用似乎符合隐式绑定(bind)规则 (object.function()) object 将是上下文对象,在此类函数调用中将使用它作为这个
  4. 因此,在 goToStore 方法中,词法选取的 this(用作上下文对象)将正确解析为组件实例

我觉得 3. 和 4. 在这里不是这种情况,因为它适用于 2. 情况:

<button onClick={this.goToStore}>test</button>

还有 this 上下文对象。

在这种特殊情况下究竟发生了什么,一步一步?

最佳答案

正如 MDN 文档所述

An arrow function does not have its own this; the this value of the enclosing execution context is used

所以你会想到

onClick={(e) => this.goToStore(e)}

作为一个匿名函数可以写成

    (e) => { 
         return this.goToStore(e) 
    }

现在在这个匿名函数中 this 指的是渲染函数的词法上下文,它又指的是 React 类实例。

现在

上下文 通常由函数的调用方式决定。当函数作为对象的方法被调用时,this 被设置为调用该方法的对象:

var obj = {
    foo: function() {
        return this;   
    }
};

obj.foo() === obj; // true

当使用 new 运算符调用函数来创建对象实例时,同样的原则也适用。当以这种方式调用时,函数范围内的 this 的值将被设置为新创建的实例:

function foo() {
    alert(this);
}

foo() // window
new foo() // foo

当作为未绑定(bind)函数调用时,这将默认为浏览器中的全局上下文或窗口对象。

所以在这里,由于函数的调用方式类似于 this.goToStore(),this 内部将引用 React 组件的上下文。

然而,当您编写 onClick={this.goToStore} 时,该函数并未执行,而是将其引用分配给 onClick 函数,稍后调用它,导致 this 在函数内部未定义,因为函数在 window 对象的上下文中运行。

现在即使 onClick={(e) => this.goToStore(e)} 有效,每当调用 render 时都会创建一个新的函数实例。在您的情况下,很容易避免,只需使用箭头函数语法创建函数 goToStore。

goToStore = (e) => {

}

查看文档以获取有关 this 的更多详细信息

关于javascript - 带有箭头函数的事件处理程序如何实现上下文绑定(bind),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47679673/

有关javascript - 带有箭头函数的事件处理程序如何实现上下文绑定(bind)的更多相关文章

  1. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  2. ruby - ruby 中的 TOPLEVEL_BINDING 是什么? - 2

    它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput

  3. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  4. ruby-on-rails - 在 ruby​​ 中使用 gsub 函数替换单词 - 2

    我正在尝试用ruby​​中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了

  5. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

  6. ruby-on-rails - 事件管理员日期过滤器日期格式自定义 - 2

    是否有简单的方法来更改默认ISO格式(yyyy-mm-dd)的ActiveAdmin日期过滤器显示格式? 最佳答案 您可以像这样为日期选择器提供额外的选项,而不是覆盖js:=f.input:my_date,as::datepicker,datepicker_options:{dateFormat:"mm/dd/yy"} 关于ruby-on-rails-事件管理员日期过滤器日期格式自定义,我们在StackOverflow上找到一个类似的问题: https://s

  7. ruby - 在 Ruby 中按名称传递函数 - 2

    如何在Ruby中按名称传递函数?(我使用Ruby才几个小时,所以我还在想办法。)nums=[1,2,3,4]#Thisworks,butismoreverbosethanI'dlikenums.eachdo|i|putsiend#InJS,Icouldjustdosomethinglike:#nums.forEach(console.log)#InF#,itwouldbesomethinglike:#List.iternums(printf"%A")#InRuby,IwishIcoulddosomethinglike:nums.eachputs在Ruby中能不能做到类似的简洁?我可以只

  8. ruby-on-rails - 创建 ruby​​ 数据库时惰性符号绑定(bind)失败 - 2

    我正在尝试在Rails上安装ruby​​,到目前为止一切都已安装,但是当我尝试使用rakedb:create创建数据库时,我收到一个奇怪的错误:dyld:lazysymbolbindingfailed:Symbolnotfound:_mysql_get_client_infoReferencedfrom:/Library/Ruby/Gems/1.8/gems/mysql2-0.3.11/lib/mysql2/mysql2.bundleExpectedin:flatnamespacedyld:Symbolnotfound:_mysql_get_client_infoReferencedf

  9. C51单片机——实现用独立按键控制LED亮灭(调用函数篇) - 2

    说在前面这部分我本来是合为一篇来写的,因为目的是一样的,都是通过独立按键来控制LED闪灭本质上是起到开关的作用,即调用函数和中断函数。但是写一篇太累了,我还是决定分为两篇写,这篇是调用函数篇。在本篇中你主要看到这些东西!!!1.调用函数的方法(主要讲语法和格式)2.独立按键如何控制LED亮灭3.程序中的一些细节(软件消抖等)1.调用函数的方法思路还是比较清晰地,就是通过按下按键来控制LED闪灭,即每按下一次,LED取反一次。重要的是,把按键与LED联系在一起。我打算用K1来作为开关,看了一下开发板原理图,K1连接的是单片机的P31口,当按下K1时,P31是与GND相连的,也就是说,当我按下去时

  10. ruby-on-rails - 事件记录 : Select max of limit - 2

    我正在尝试将以下SQL查询转换为ActiveRecord,它正在融化我的大脑。deletefromtablewhereid有什么想法吗?我想做的是限制表中的行数。所以,我想删除少于最近10个条目的所有内容。编辑:通过结合以下几个答案找到了解决方案。Temperature.where('id这给我留下了最新的10个条目。 最佳答案 从您的SQL来看,您似乎想要从表中删除前10条记录。我相信到目前为止的大多数答案都会如此。这里有两个额外的选择:基于MurifoX的版本:Table.where(:id=>Table.order(:id).

随机推荐