得益于class properties proposal,React的代码变得简洁了许多。在React中处理this绑定的时候,也习惯性地使用属性声明来替代过去constructor
赋值的方式git
class A extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
// do something
}
}
// arrow function
class B extends React.Component {
handleClick = () => {
// do something
}
}
复制代码
箭头函数在声明属性的时候自动绑定 this
,省去了在constructor
中的函数覆盖操做。es6
可是使用arrow function真的就一本万利了吗?github
// code 1
class Base {
commonHandler = () => {
// do something
console.log('Base commonHandler', this.text);
}
text = 'base'
selfHandler() {
console.log('selfHandler')
}
}
class A extends Base {
text = 'A'
commonHandler(){
console.log('A commonHandler', this.text);
}
}
const a = new A();
a.commonHandler(); // Base commonHandler A
复制代码
上述代码最终的执行会有点让人意外,为何text属性发生了覆盖,而commonHandler的函数却仍是执行父类?babel
咱们经过babel编译来先来看下这段代码在es2017下的结果函数
class Base {
constructor() {
// commonHandler被移到了constructor中
this.commonHandler = () => {
// do something
console.log('excute commonHandler', this.text);
};
this.text = 'base';
}
selfHandler() {
console.log('selfHandler');
}
}
复制代码
能够看到text
属性和箭头函数commonHandler
全被移到constuctor
中,而正常成员方法selfHandler
则没有改变。es6的class中能够经过相似寄生组合式继承进行模拟,编译结果fetch
class A
执行继承的后在constructor
中将会调用父类的构造函数,而成员方法commonHandler
挂载到了A的prototype上,实例化后按照方法查找的顺序,先获取的是实例上的方法。能够经过将code 1中的a.commonHandler()
替换为a.__proto__.commonHandler()
输出了预期覆盖父类方法的的结果'A commonHandler A'。优化
补充:class中的super在做为对象使用时,在普通方法中指向的是父的原型对象,因此若是父类的方法是经过arrow function定义
fn
,则该方法在子类中将没法经过相似super.fn()
进行调用ui
那咱们是否是能够在子类中也经过arrow function对commonHandler
进行绑定以达到覆盖的目的?this
就结果而言的确这样作,能够根据上述对arrow function的分析,每指定一个arrow function都将会在contructor
中出现,也就意味着多个地方实例化,将会建立多个方法,而不是像一般定义在原型上面,这样定义的方法在全部的实例上共享。lua
那是否是意味着咱们要抛弃使用arrow function,答案是否认,咱们这里要杜绝的是滥用,仅仅作有必要绑定的。好比onClick={this.doSomething}
或fetch.then(this.hanldeDone)
附上一个优化方案:autobind-decorator核心思路是仅在必要时绑定做用域
参考: Arrow Functions in Class Properties Might Not Be As Great As We Think