资讯专栏INFORMATION COLUMN

从 React 绑定 this,看 JS 语言发展和框架设计

jemygraw / 443人阅读

摘要:在语言中,关于这个关键字的行为一直以来困扰着一代又一代初级开发者。同时,也充分反应了的诡异与灵活。这种情况下,无法自动绑定。总结本文在对比绑定的五种方法的同时,也由远及近了解了语言的发展从的,到的箭头函数,再到对的改进。

在 javascript 语言中,关于 this 这个关键字的行为一直以来困扰着一代又一代初级开发者。同时 this,也充分反应了 javascript 的诡异与灵活。

但是请别误会,这篇文章并不会对 this 的特征进行全方位讲解,因为这些内容都可以在各种前端书籍中找到答案。这里,我试图结合 React 事件处理函数关于 this 绑定的演化史,谈一谈这个框架设计以及 javascript 语言在这一细节上的进步和完善。同时对比 this 绑定的不同方案,让大家对 React 、ES next 有一个更清晰的认识。

React 处理 this 上下文环境已经有至少五年历史了。五年期间,方案辈出,我们先来总结一下。

方法一:React.createClass 自动绑定

React 中创建组件的方式已经很多,比较古老的诸如 React.createClass 应该很多人并不陌生。当然,从 React 0.13 开始,可以使用 ES6 Class 代替 React.createClass 了,这应该是今后推荐的方法。
但是需要知道,React.createClass 创建的组件,可以自动绑定 this。也就是说,this 这个关键字会自动绑定在组件实例上面。

// This magically works with React.createClass
// because `this` is bound for you.
onChange = {this.handleChange}

当然很遗憾,对于组件的创建,官方已经推荐使用 class 声明组件或使用 functional 无状态组件:

Later, classes were added to the language as part of ES2015, so we added the ability to create React components using JavaScript classes. Along with functional components, JavaScript classes are now the preferred way to create components in React.

For your existing createClass components, we recommend that you migrate them to JavaScript classes.

我认为,这其实是 React 框架本身的自我完善和对未来的迎合,是框架和语言发展的大势所趋。

方法二:渲染时绑定

通过前文,我们知道最传统的组件创建方式不会有 this 绑定的困扰。接下来,我们假定所有的组件都采取 ES6 classes 方式声明。这种情况下,this 无法自动绑定。一个常见的解决方案便是:

onChange = {this.handleChange.bind(this)}

这种方法简明扼要,但是有一个潜在的性能问题:当组件每次重新渲染时,都会有一个新的函数创建。OMG! 这听上去貌似是一个很大的问题,但是其实在真正的开发场景中,由此引发的性能问题往往不值一提(除非是大型组件消费类应用或游戏)。

方法三:箭头函数绑定

这种方法其实和第二种类似,拜 ES6 箭头函数所赐,我们可以隐式绑定 this:

onChange = {e => this.handleChange(e)}

当然,也与第二种方法一样,它同样存在潜在的性能问题
下面将要介绍的两种方法,可以有效规避不必要的性能消耗,请继续阅读。

方法四:Constructor 内绑定

constructor 方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。

所以我们可以:

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

这种方式往往被推荐为“最佳实践”,也是笔者最为常用的方法。

但是就个人习惯而言,我认为与前两种方法相比,constructor 内绑定在可读性和可维护性上也许有些欠缺。
同时,我们知道在 constructor 声明的方法不会存在实例的原型上,而属于实例本身的方法。每个实例都有同样一个 handleChange,这本身也是一种重复和浪费。

如果你对 ES next 一直抱有开放的思想,且能够使用 stage-2 的特性,不妨尝试一下最后一种方案。

方法五:Class 属性中使用 = 和箭头函数

这个方法依赖于 ES next 的新特性,请参考 tc 39: Public Class Fields

handleChange = () => {
      // call this function from render 
      // and this.whatever in here works fine.
};

我们来总结一下这种方式的优点:

使用箭头函数,有效绑定了 this;

没有第二种方法和第三种方法的潜在性能问题;

避免了方法四的组件实例重复问题;

我们可以直接从 ES5 createClass 重构得来。

总结

本文在对比 React 绑定 this 的五种方法的同时,也由远及近了解了 javascript 语言的发展:从 ES5 的 bind, 到 ES6 的箭头函数,再到 ES next 对 class 的改进。

React 作为蓬勃发展的框架也同样在与时具进,不断完善,结合语言特性的发展不断调整着自身。

最后,我们通过这张图片来完整回顾:

本文参考了 Cory House 的文章:5 Approaches for Handling this,并在此基础上进行延伸。

我的其他一些关于 React 文章:

React 组件设计和分解思考

做出Uber移动网页版还不够 极致性能打造才见真章

解析Twitter前端架构 学习复杂场景数据设计

React Conf 2017 干货总结1: React + ES next = ♥

React+Redux打造“NEWS EARLY”单页应用 一个项目理解最前沿技术栈真谛

一个react+redux工程实例

......

Happy Coding!

PS: 作者Github仓库,欢迎通过代码各种形式交流。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/83866.html

相关文章

  • React 应用设计之道 - curry 化妙用

    摘要:右侧展现对应产品。我们使用命名为的对象表示过滤条件信息,如下此数据需要在组件中进行维护。因为组件的子组件和都将依赖这项数据状态。化应用再回到之前的场景,我们设计化函数,进一步可以简化为对于的偏应用即上面提到的相信大家已经理解了这么做的好处。 showImg(https://segmentfault.com/img/remote/1460000014458612?w=1240&h=663...

    sewerganger 评论0 收藏0
  • React 应用设计之道 - curry 化妙用

    摘要:右侧展现对应产品。我们使用命名为的对象表示过滤条件信息,如下此数据需要在组件中进行维护。因为组件的子组件和都将依赖这项数据状态。化应用再回到之前的场景,我们设计化函数,进一步可以简化为对于的偏应用即上面提到的相信大家已经理解了这么做的好处。 showImg(https://segmentfault.com/img/remote/1460000014458612?w=1240&h=663...

    LinkedME2016 评论0 收藏0
  • 探索 Redux4.0 版本迭代 论基础谈展望(对比 React context)

    摘要:在几天前发布了新版本,被合入。但是在版本迭代的背后很多有趣的设计值得了解。参数处理这项改动由提出。对透明化处理中的,达到将包裹起来的目的。对的冻结认为,在中使用和方法是一种反模式。尤其是这样的新,某些开发者认为将逐渐取代。 showImg(https://segmentfault.com/img/remote/1460000014571148); Redux 在几天前(2018.04....

    yiliang 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<