方式
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
区别
-
正确调用的方式的不同
若在上面的示例中的两个按钮上面加上如下的点击事件:
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方法内部的this为undefined,之所以出现这种情况,原因在于用这种方式进行定义的方法,其内部this的具体指向需要等到运行时才会进行动态的绑定。上面代码中将doClick方法赋值给了button的点击事件,而this会指向所属函数的调用者(拥有者),点击事件由浏览器的事件处理线程进行执行,这时this的指向便不再是当前类的实例了。解决办法有两种:
-
在类的
constructor中进行手动绑定:constructor(props) { super(props); this.doClick = this.doClick.bind(this); }即通过
bind方法将doClick方法内部的this绑定到当前类的实例并返回了一个新的函数, 然后将新函数赋值给类的自有属性doClick,当点击按钮调用doClick方法时,则是调用的这个新函数。 -
在调用的时候用箭头函数进行包裹:
<button onClick={() => this.doClick()}>click</button>这样做也可以正确运行,是因为箭头函数内部本身不存在
this,箭头函数内部的this即是外层的this,而且this的绑定在定义时便已完成并固定,会绑定到函数所属的对象,而不是在运行时动态绑定的。所以这里的this.doClick()的this指向的是render方法里面的this,即当前类的实例,那么由实例去调用doClick方法,则可以保证doClick方法里面的this也是正确指向当前实例的。但是,这种解决方式是不值得推荐的,因为没必要多加一层没有额外操作的匿名函数,而且每次
render时,都会创建不同的匿名函数,当这个匿名函数被当做prop向下传递时,可能会导致子元素会做额外的重新渲染。
根据上面的解释,使用箭头函数定义的
onClick2在不经过额外的处理后,可以直接赋值给按钮的点击事件并能够正确运行就不难理解了。 -
-
存在于类的位置不同
使用常规方式定义的方法,存在于类的原型对象上面,子类是可以继承到此方法的;而使用箭头函数定义的方法则属于类的自有方法, 子类是无法继承的。