V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
yazoox
V2EX  ›  JavaScript

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

  •  
  •   yazoox · 2020-07-15 17:05:04 +08:00 · 2027 次点击
    这是一个创建于 1599 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

    
    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,啥时候直接引用?

    谢谢!

    18 条回复    2020-07-16 14:51:35 +08:00
    ChanKc
        1
    ChanKc  
       2020-07-15 17:14:36 +08:00 via Android
    1 希望函数内的 this 和函数外的 this 都指向同一个对象,用箭头函数。希望写成构造函数,就要携程普通函数,但是这个时候你可以直接用 class 的写法,更现代更易于阅读
    2 啥时候都不要用 bind,除了以下两个情况:一是把 ArrayLike 且非 iterable 的东西转数组或调用数组的方法,二是对使用 Object.create(null)生成的对象使用 Object 的原型上的方法
    ChanKc
        2
    ChanKc  
       2020-07-15 17:28:22 +08:00 via Android
    噢你说的是 bind,好像就更没有用了
    我说的主要适用于 call 和 apply,不过 bind 和它们也有类似的地方
    在现代的 JavaScript 里真的没什么用了
    xbrave
        3
    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
        4
    yazoox  
    OP
       2020-07-15 18:01:36 +08:00
    @ChanKc @xbrave 汇总下来,似乎都是有关'this'这个概念。JS 怎么把 this 整得这么复杂......
    mingtianjiayou
        5
    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
        6
    ChanKc  
       2020-07-15 18:06:26 +08:00 via Android
    @yazoox 所以有人发明了 this-free 编程范式,Douglas Crockford 就很喜欢这种,可以完全不用 this 在 JS 中编程。但是如果你用了用到 this 的库就几乎不可避免要学习相关的知识
    ChanKc
        7
    ChanKc  
       2020-07-15 18:09:35 +08:00 via Android
    #6 具体可以看 Douglas Crockford 的书 How JavaScript Works 第十七章 How Class Free Works
    yazoox
        8
    yazoox  
    OP
       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
        9
    ChanKc  
       2020-07-15 18:19:38 +08:00 via Android
    @yazoox 还有一个办法就是:永远不要在类的方法以外的函数内使用 this,这样就不容易搞错了
    mingtianjiayou
        10
    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
        11
    ChanKc  
       2020-07-15 18:28:36 +08:00 via Android
    @yazoox 我想了一下,class methods 指的是原型链上的方法,而不是对象上的方法。我没写过 react,我猜是 react 只能调用对象上的方法?
    你写的 myclass,A 和 B 应该都是 myclass.prototype 这个对象的方法
    ChanKc
        12
    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
        13
    IsaacYoung  
       2020-07-15 19:43:41 +08:00
    class arrow function 原型上没有这个函数

    bind 的方式有
    KuroNekoFan
        14
    KuroNekoFan  
       2020-07-15 20:39:06 +08:00 via iPhone
    this free is good,就应该用且仅用参数来传递信息
    azcvcza
        15
    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
        16
    ChanKc  
       2020-07-16 12:57:19 +08:00
    另外主楼里的 handleCheck 和 handleClick 方法的一大区别是后面的等号
    handleC
    ChanKc
        17
    ChanKc  
       2020-07-16 13:00:25 +08:00
    #16 手抖变成了回复……
    另外主楼里的 handleCheck 和 handleClick 方法的一大区别是后面的等号
    handleCheck = () => {}
    这句实际上是 https://github.com/tc39/proposal-class-fields 的语法,因此方法是在对象上而不是在原型上,因此不需要在构造器里面再 bind handleCheck
    cxyct2
        18
    cxyct2  
       2020-07-16 14:51:35 +08:00 via Android   ❤️ 1
    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()会报错
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2635 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 10:51 · PVG 18:51 · LAX 02:51 · JFK 05:51
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.