class - function ES6类的方法的两种定义方式及调用方式

2 篇文章 0 订阅
1 篇文章 0 订阅

方式

import * as React from 'react';

const { PureComponent, Fragment } = React;

class Test extends PureComponent {
    render() {
        return (
            <Fragment>
                <button>click</button>
                <button>click2</button>
            </Fragment>
        );
    }
    // 方式一,常规定义方式
    doClick() {
        console.log(this);
    }
    // 方式二,箭头函数定义方式
    doClick2 = () => {
        console.log(this);
    }
}

export default Test

区别

  1. 正确调用的方式的不同

    若在上面的示例中的两个按钮上面加上如下的点击事件:

    render() {
        return (
            <Fragment>
                <button onClick={this.doClick}>click</button>
                <button onClick={this.doClick2}>click2</button>
            </Fragment>
        );
    }
    

    分别点击两个按钮后,会打印出上面信息?是这样的:

    doClick() {
        console.log(this);  // undefined
    }
    
    doClick2 = () => {
        console.log(this);  // Test {props: {…}, context: {…}, refs: {…}, updater: {…}, state: {…}, …}
    }
    

    使用方式一进行定义的 doClick 方法内部的 thisundefined,之所以出现这种情况,原因在于用这种方式进行定义的方法,其内部 this 的具体指向需要等到运行时才会进行动态的绑定。上面代码中将 doClick 方法赋值给了 button 的点击事件,而 this 会指向所属函数的调用者(拥有者),点击事件由浏览器的事件处理线程进行执行,这时 this 的指向便不再是当前类的实例了。

    解决办法有两种:

    1. 在类的 constructor 中进行手动绑定:

      constructor(props) {
          super(props);
          this.doClick = this.doClick.bind(this);
      }
      

      即通过 bind 方法将 doClick 方法内部的 this 绑定到当前类的实例并返回了一个新的函数, 然后将新函数赋值给类的自有属性 doClick ,当点击按钮调用 doClick 方法时,则是调用的这个新函数。

    2. 在调用的时候用箭头函数进行包裹:

      <button onClick={() => this.doClick()}>click</button>
      

      这样做也可以正确运行,是因为箭头函数内部本身不存在 this ,箭头函数内部的 this 即是外层的 this ,而且 this 的绑定在定义时便已完成并固定,会绑定到函数所属的对象,而不是在运行时动态绑定的。所以这里的 this.doClick()
      this 指向的是 render 方法里面的 this ,即当前类的实例,那么由实例去调用 doClick 方法,则可以保证 doClick 方法里面的 this 也是正确指向当前实例的。

      但是,这种解决方式是不值得推荐的,因为没必要多加一层没有额外操作的匿名函数,而且每次 render 时,都会创建不同的匿名函数,当这个匿名函数被当做 prop 向下传递时,可能会导致子元素会做额外的重新渲染。

    根据上面的解释,使用箭头函数定义的 onClick2 在不经过额外的处理后,可以直接赋值给按钮的点击事件并能够正确运行就不难理解了。

  2. 存在于类的位置不同

    使用常规方式定义的方法,存在于类的原型对象上面;而使用箭头函数定义的方法则属于类的自有方法,但不同于通过 static 方式定义的方法,因为类本身无法调用到该方法,但通过类创建的实例上是存在该方法的。无论是那种定义方式子类都可以继承到。如下示例:

    class C {
        func = () => { return 1 }
        func2() {
            return 2
        }
    }
    class C1 extends C {
        static func3() {
            return 3
        }
    }
    const c = new C()
    const c1 = new C1()
    
    C.prototype 	// {constructor: ƒ, func2: ƒ}
    C.func	// undefined
    c	// C {func: ƒ}
    c.func()	// 1
    c.func2()	// 2
    
    
    C1.prototype	// {constructor: ƒ}
    C1.func	// undefined
    C1.func3()	// 3
    c1	// C1 {func: ƒ}
    c1.func()	// 1
    c1.func2()	// 2
    
  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值