[阅 #36] 在写 React 代码时,用类属性和在构造器中用 bind 哪个内存使用更少
「阅」——JSCourse 旗下栏目,专门推荐我们为大家精心挑选的优质 JavaScript 相关技术内容
在写 React 代码的时候,Render 函数中,往往需要调用当前组件实例中定义的函数,这个时候我们需要解决被调函数中 this 的指向问题,一般我们都会采取三个方案:
- 用类属性
- 用 bind
- 用 inline function
inline function 就像这样:
class MyComponent extends React.Component {
render() {
const msg = "Hello " + this.props.user.name.first;
return <PureChild onClick={() => this.props.onAlert(msg)} />;
}
}
今天不讨论 inline function,下期会介绍这部分。今天主要讨论前两者,因为小编最近读到了一篇 Donavon West 的文章——Demystifying Memory Usage using ES6 React Classes: https://medium.com/dailyjs/demystifying-memory-usage-using-es6-react-classes-d9d904bc4557(记得梯子),主要讲解了前两者在内存使用上的情况。
我们先来看看使用类属性是怎么样的:
class MyClass extends Component {
constructor() {
super();
this.state = { clicks: 0 };
}
handler = () => {
this.setState(({ clicks }) => ({ clicks: clicks + 1 }));
}
render() {
const { clicks } = this.state;
return(
<button onClick={this.handler}>
{`You've clicked me ${clicks} times`}
</button>
);
}
}
上述代码相信绝大部分写过 React 的同学都能看懂,重点在 handler 属性这里,它将一个箭头函数表达式赋值给了 handler 属性。这里其实用了 ES 新特性——类属性,由于浏览器大多尚未支持该特性,一般我们会用 babel 进行 transform,而 babel 在对类属性进行 transform 的时候,这里的 handler 是直接绑定在实例上的,你可以直接用 babel 转下看看就知道了,而具体原因可以看 babel 文档——https://babeljs.io/docs/plugins/transform-class-properties/,那么也就说,每个实例都对 handler 属性会有较大的内存开销。
我们再来看看在构造函数中直接 bind 的例子:
class MyClass extends Component {
constructor() {
super();
this.state = { clicks: 0 };
this.handler = this.handler.bind(this);
}
handler() {
this.setState(({ clicks }) => ({ clicks: clicks + 1 }));
}
render() {
const { clicks } = this.state;
return(
<button onClick={this.handler}>
{`You've clicked me ${clicks} times`}
</button>
);
}
}
这里就用了 bind 来修正 this 的指向,这种和上一种的区别就是,这种情况下每个实例中的 handler 只保存了对其基类中 handler 函数的一种引用,最终是会去调用基类中的 handler 函数的。等效的 ES5 代码差不多这样:
function MyClass() {
this.handler = this.handler.bind(this);
}
MyClass.prototype.handler = function handler () {...}
这种情况下,每个实例对 handler 的内存开销就会小很多。下面是两种情况下,内存使用大致示意图,其中实线的框表示内存开销相对略大,虚线则表示相对比较小。
当然了,分享这个只是让大家对这方面的知识知晓下,实际上一方面只有当你有大量实例创建出来的时候,这种内存的开销差异才会体现得比较明显(比如:ListView),另外一方面,尽管类属性的写法理论上内存开销相对较大,但是写起来很方便,而且可读性也很好,所以,绝大部分情况下,除非这点性能差异对你的应用而言非常重要,否则小编觉得还是应该以可读写和书写便利性为先,再者 babel 自身的 transform 也有优化的可能,这部分的内存开小差异也可能会被尽可能地缩小甚至避免。
最后分享一则娱乐消息:美剧《硅谷》第五季将于 3月12日 开播,HBO 已经放出了第五季的预告片(自备梯子)——https://www.youtube.com/watch?v=lRs72x7Lgtc,有兴趣的同学如果还没看过前面四季的话不妨去补一下,它每季之间剧情还是有一定关联的。
好了,以上就是本期内容,我们下期再见咯,提前祝大家周末愉快!
关注「jscourse」微信公众号获取更多 JavaScript 学习课程和资料!