请教一个在 javascript 中,组件的事件绑定的问题。(和 react 应该没关系)

2020-07-15 17:05:04 +08:00
 yazoox

最近学习,浏览代码,经常看到组件里面绑定事件时,有两种用法,

不知道两者有啥关系 /区别,或者应该在什么情况下使用哪种,特来请教一下。


class A extends React.Component {

handleClick(parameter) {

}

handleCheck = () => {

}

render() {
  return (
    <component
      onClick={this.handleClick.bind(this, parameter)}
      onCheck={this.handleCheck}
    > 
      
    </component>
  
  )
}
}

如上所未,class 内的成员函数,有两种写法,一种普通的,一种 arrow function

同样,在组件属性指定时,有的需要调用.bind(this),有的就是直接引用函数了。

这两种用法,有啥不一样?

  1. 啥时候用普通函数写法,啥时候用 arrow function ?
  2. 啥时候需要 bind,啥时候直接引用?

谢谢!

2045 次点击
所在节点    JavaScript
18 条回复
ChanKc
2020-07-15 17:14:36 +08:00
1 希望函数内的 this 和函数外的 this 都指向同一个对象,用箭头函数。希望写成构造函数,就要携程普通函数,但是这个时候你可以直接用 class 的写法,更现代更易于阅读
2 啥时候都不要用 bind,除了以下两个情况:一是把 ArrayLike 且非 iterable 的东西转数组或调用数组的方法,二是对使用 Object.create(null)生成的对象使用 Object 的原型上的方法
ChanKc
2020-07-15 17:28:22 +08:00
噢你说的是 bind,好像就更没有用了
我说的主要适用于 call 和 apply,不过 bind 和它们也有类似的地方
在现代的 JavaScript 里真的没什么用了
xbrave
2020-07-15 17:54:15 +08:00
建议阅读 React 文档官网上的 handling Events 这一节:https://reactjs.org/docs/handling-events.html
You have to be careful about the meaning of this in JSX callbacks. In JavaScript, class methods are not bound by default. If you forget to bind this.handleClick and pass it to onClick, this will be undefined when the function is actually called.

This is not React-specific behavior; it is a part of how functions work in JavaScript. Generally, if you refer to a method without () after it, such as onClick={this.handleClick}, you should bind that method.

If calling bind annoys you, there are two ways you can get around this. If you are using the experimental public class fields syntax, you can use class fields to correctly bind callbacks
yazoox
2020-07-15 18:01:36 +08:00
@ChanKc @xbrave 汇总下来,似乎都是有关'this'这个概念。JS 怎么把 this 整得这么复杂......
mingtianjiayou
2020-07-15 18:02:50 +08:00
这俩是 js 中绑定 this 的两种方式:
public class fields 语法,this 已经绑定,可以直接调用
```js
handleClick = () => {
console.log('this is:', this);
}
```

这种需要,调用时用 bind 手动绑定 this
```js
handleClick(parameter) {

}
```

还有一种,也可以在回调中使用箭头函数
```jsx
<button onClick={() => this.handleClick()}>
Click me
</button>
```

目的都是为了确保函数内可以正确的访问到 this,除了写法上的,感觉没有什么区别。。
附个 react 的链接 https://zh-hans.reactjs.org/docs/handling-events.html
ChanKc
2020-07-15 18:06:26 +08:00
@yazoox 所以有人发明了 this-free 编程范式,Douglas Crockford 就很喜欢这种,可以完全不用 this 在 JS 中编程。但是如果你用了用到 this 的库就几乎不可避免要学习相关的知识
ChanKc
2020-07-15 18:09:35 +08:00
#6 具体可以看 Douglas Crockford 的书 How JavaScript Works 第十七章 How Class Free Works
yazoox
2020-07-15 18:17:18 +08:00
@ChanKc @mingtianjiayou 对于这句话,我有点疑问
“ In JavaScript, class methods are not bound by default.".

如果这样的话,那一个标准的 class 下面,自己的成员函数,都不能互相调用了? e.g.
下面这个 myclass,没有显示的 bind A&B,但是,实际上是可以这么用的。

class myclass {
function A() {}
function B() {
this.A(); // 实际上,这么用是没有问题的呢。
}
}
ChanKc
2020-07-15 18:19:38 +08:00
@yazoox 还有一个办法就是:永远不要在类的方法以外的函数内使用 this,这样就不容易搞错了
mingtianjiayou
2020-07-15 18:28:29 +08:00
@yazoox 要看你是怎么调用 B 的,普通函数内的 this 取决于它的执行环境,附个链接 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/this
ChanKc
2020-07-15 18:28:36 +08:00
@yazoox 我想了一下,class methods 指的是原型链上的方法,而不是对象上的方法。我没写过 react,我猜是 react 只能调用对象上的方法?
你写的 myclass,A 和 B 应该都是 myclass.prototype 这个对象的方法
ChanKc
2020-07-15 19:00:19 +08:00
#8 @yazoox
参考以下代码
class Adder {
constructor(a, b) {
this.a = a;
this.b = b;
}

add() {
return this.a + this.b
}
}
let a = new Adder(1, 3);
a.add(); // 4
Object.setPrototypeOf(a, null);
a.add(); // Uncaught TypeError: a.add is not a function

class AnotherAdder {
constructor(a, b) {
this.a = a;
this.b = b;
this.add = this.add.bind(this);
}

add() {
return this.a + this.b
}
}
let b = new AnotherAdder(1, 3);
b.add(); // 4
Object.setPrototypeOf(b, null);
b.add(); // 4
IsaacYoung
2020-07-15 19:43:41 +08:00
class arrow function 原型上没有这个函数

bind 的方式有
KuroNekoFan
2020-07-15 20:39:06 +08:00
this free is good,就应该用且仅用参数来传递信息
azcvcza
2020-07-16 09:15:55 +08:00
react 官方文档提倡的写法 1,constructor 里绑好 this.xxx = this.xxx.bind(this),然后再 onClick={this.xxx} 2, xxx = () =>{}, onClick={this.xxx}
ChanKc
2020-07-16 12:57:19 +08:00
另外主楼里的 handleCheck 和 handleClick 方法的一大区别是后面的等号
handleC
ChanKc
2020-07-16 13:00:25 +08:00
#16 手抖变成了回复……
另外主楼里的 handleCheck 和 handleClick 方法的一大区别是后面的等号
handleCheck = () => {}
这句实际上是 https://github.com/tc39/proposal-class-fields 的语法,因此方法是在对象上而不是在原型上,因此不需要在构造器里面再 bind handleCheck
cxyct2
2020-07-16 14:51:35 +08:00
class A {
      constructor (props) {
        this.props = props
        this.printProps = this.printProps
      }
      printProps = function () {
        return this.props
      }
    }
    (function () {
      const a = new A('haha')
      console.log(a.printProps())
      const fun = a.printProps
      console.log(fun())
    })();
如果不绑 this 的话 a.printProps()不会报错,但是 fun()会报错

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/690298

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX