javascript 绑定 vs 箭头函数(用于响应 onClick 事件)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/50375440/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Binding vs arrow-function (for react onClick event)
提问by Kyle Woolley
So I am trying to learn react and got a little mixed up with understanding .bind(this)in the constructor. However I think I understand it now and just want to know why I would use that vs an arrow function in the onClick. See code below:
所以我正在尝试学习 react 并且.bind(this)在构造函数中有点混淆。但是我想我现在明白了,只是想知道为什么我会在 onClick 中使用它而不是箭头函数。见下面的代码:
Binding method makes sure 'this' in eventClick function references the class
绑定方法确保 eventClick 函数中的“this”引用该类
Class Click extends react.Component {
constructor(props) {
super(props)
this.clickEvent = this.clickEvent.bind(this);
}
render = () => (
<button onClick={this.clickEvent}>Click Me</button>
)
clickEvent() {console.log(this)} // 'this' refers to the class
}
However this method also references the class. Is there any pro/con to use one vs the other?
但是,此方法也引用了该类。使用一个和另一个有什么优点/缺点吗?
Class Click extends react.Component {
render = () => (
<button onClick={() => {this.clickEvent()}}>Click Me</button>
)
clickEvent() {console.log(this)} // 'this' refers to the class
}
回答by Top-Master
First of all, let's see an example of each technique.
首先,让我们看一下每种技术的示例。
Binding:
捆绑:
import React from 'react';
class MyComponent extends React.Component {
constructor(props) {
super(props)
this.clickHandler = this.clickHandler.bind(this);
}
clickHandler() {
console.log( this )
}
render() {
return <button onClick={this.clickHandler}>Click Me</button>
}
}
Arrow-function:
箭头功能:
import React from 'react';
class MyComponent extends React.Component {
constructor(props) {
super(props)
}
clickHandler = () => {
console.log( this )
}
render() {
return <button onClick={this.clickHandler}>Click Me</button>
}
}
Pros and Cons:
优点和缺点:
Using the Arrow-function on public-class-field is more human-readable, because of fewer lines of code, But keep in mind that using Arrow-function can affect two things:
在 public-class-field 上使用 Arrow-function 更易读,因为代码行更少,但请记住,使用 Arrow-function 会影响两件事:
First the?memory and performance; When you use a class field to define a function, your whole method resides on?each instance of the class?and NOT on the prototype, but using the?bindtechnic, just a small callbackis stored on each instance, which calls your method that is stored on the prototype.
首先是?内存和性能;当您使用类字段定义函数时,您的整个方法驻留在?类的每个实例?而不是在原型上,而是使用?绑定技术,callback每个实例上只存储一小部分,它调用存储在原型上的方法。
Second thing that can be affected is how you write your?unit tests. You won't be able to use the component prototype to stub on function calls like below:
可能受到影响的第二件事是您如何编写单元测试。您将无法使用组件原型来存根如下函数调用:
const spy = jest.spyOn(MyComponent.prototype, 'clickHandler');
expect(spy).toHaveBeenCalled();
You will have to find another way to stub the method, either by?passing the spy in props?or?checking the state changes.
您将不得不找到另一种方法来存根该方法,要么通过?通过道具中的间谍?或者?检查状态变化。
Conclusion
结论
Computers are really good at reading code; you shouldn't worry about that. You may want to consider making your code more human-readable by using a class-property arrow-function.
计算机非常擅长阅读代码;你不应该担心这个。您可能需要考虑通过使用类属性箭头函数使您的代码更具人类可读性。
But When you want to keep both human-readability and performance, consider using plugin-transform-arrow-functionsplugin (although v7.2.0caused problemsfor me), just run npm i --save-dev @babel/plugin-transform-arrow-functionsand add it into your "babel.config.js" or ".babelrc" file, like:
但是当你想要同时保持人类可读性和性能时,可以考虑使用plugin-transform-arrow-functions插件(虽然对我v7.2.0造成了问题),只需运行npm i --save-dev @babel/plugin-transform-arrow-functions并将其添加到“ babel.config.js”或“ .babelrc”文件中,例如:
{
"presets": ["module:metro-react-native-babel-preset"],
"plugins": [
["@babel/plugin-proposal-decorators", { "decoratorsBeforeExport": false }],
["@babel/plugin-transform-arrow-functions", { "spec": true }]
]
}
You could also use something like auto-bind decorator, which would turn above example into:
您还可以使用类似auto-bind 装饰器的东西,它将上面的例子变成:
import React from 'react';
import { boundMethod as bind } from 'autobind-decorator';
class MyComponent extends React.Component {
constructor(props) {
super(props)
}
@bind
clickHandler() {
console.log( this )
}
render() {
return <button onClick={this.clickHandler}>Click Me</button>
}
}
Note: It is unnecessary to put
@bindon every function. You only need to bind functions that you pass around. e.g.onClick={this.doSomething}Orfetch.then(this.handleDone)
注意:没必要把
@bind每一个功能都装上。您只需要绑定您传递的函数。例如onClick={this.doSomething}或fetch.then(this.handleDone)
回答by T.J. Crowder
Your second example recreates the function on every render. In your first, you create the bound function just once.
您的第二个示例在每个render. 首先,您只需创建一次绑定函数。
You could just create the handler in the constructor as an arrow function:
您可以在构造函数中将处理程序创建为箭头函数:
class Click extends react.Component {
constructor(props) {
super(props)
this.clickEvent = () => { // ***
console.log(this); // ***
}; // ***
}
render = () => (
<button onClick={this.clickEvent}>Click Me</button>
)
}
Using the class fields proposal syntax(which is enabled in the transpiler settings of most React projects, and which you're using for your renderfunction), you can write that like this:
使用类字段建议语法(在大多数 React 项目的转译器设置中启用,并且您将其用于您的render函数),您可以这样编写:
class Click extends react.Component {
constructor(props) {
super(props)
}
clickEvent = () => { // ***
console.log(this); // ***
}; // ***
render = () => (
<button onClick={this.clickEvent}>Click Me</button>
)
}
Which is the same thing.
这是同一件事。
Side note: You're creating a separate renderfunction for each instance of your class. There's no need to do that, it can be on the prototype. So:
旁注:您正在render为类的每个实例创建一个单独的函数。没有必要这样做,它可以在原型上。所以:
class Click extends react.Component {
constructor(props) {
super(props)
}
clickEvent = () => {
console.log(this);
};
render() {
return <button onClick={this.clickEvent}>Click Me</button>;
}
}

