攻城师 2019-06-21
React发布的时候,很多人看到JSX都迷失方向(lost their minds)。javascript中的那些括号是干什么的?! 那么关注点分离理念呢? Facebook没有从社区中引荐什么吗?
至少可以这样说,和很多人一样,我对JSX最初的反应也是持怀疑态度的(skeptical)。但是当我渐渐喜欢上React的时候,每当我介绍给新开发者,我就感觉在秀自己的丑宝宝(作者真幽默,还秀上了自
己爱子照片,这里省略掉)。
尽管有最初的想法,但后来我意识到JSX根本不是激进的(radical)想法。实际上,这就是事情的另一面。这是自然的演化转换过程。(It’s a natural evolutionary transition.) 为了理解为什么是这
样,请看后续故事。
非侵入式Javascript就是说HTML标签中不嵌入任何javascript代码。还记得jquery时代的那些日子吗? 非侵入式Javascript时代可谓百花齐放(in full bloom)。HTML是纯HTML, Javascript也是纯Javascript。关注点是完全分离的。
HTML代码可以这样写:
<a class=”hide”>Click to hide me</a>
Javascript代码可以这样写:
$('.hide').click(function() {- $(this).hide(); }-
完胜了,是不是? 其实不然。
似乎这是非常棒的思想。 HTML完全纯正!但是随后我们会发现一些问题: 我们怎么告知两者的互联关系呢? 答案是: 除非看完Javascript的每行代码,否则不能确定两者关系是啥。 这种模式中,要修>改HTML标签中的某行,就必须检查javascript中的每一行来确保这样修改没有破坏选择器。你瞧,这里实际上并没有做到完全的分离。确实,JS和HTML是在独立文件中了,但是这两个技术基本上是完全
联系在一起的(骨肉相连??join at the hip)。两者必须步调一致(lockstep),否则应用将会奔溃。
严格的HTML和JS的分离,实际上导致应用难于维护调试。每当修改标签行的时候,必须考虑是否破坏某个jQuery选择器。也许放宽对关注分离的信仰,我们也许会可能会减轻一些痛苦吧。(Perhaps if we relaxed our religious devotion to separation of concerns, we could relieve some of this pain?)这就迎来了第二个阶段的故事…
当前端开发看到Knockout和Angular的双向绑定的时候,这是一个启发。我们就在关注点分离与HTML中包含强大声明绑定之间摇摆。(Many of us tossed our religious devotion to separation of concerns and embraced the power of declaring bindings in HTML.)当数据改变的时候,UI就更新。当UI改变的时候,数据也随之改变。如此干净,如此简单。
的确,每个类库和框架都有自己的一套实现方式,但是基本上做的都是同样的事情。简单看看几个流行框架中对数组迭代的简单例子:
//Angular <div ng-repeat="user in users"> //Ember {{#each user in users}} //Knockout data-bind="foreach: users"
这里好戏上演了。 几乎没有人意识到一个非常基本的问题: 这里我们实际上在HTML中放入了Javascript。这就不符合关注点分离的理念。上面所有的方法都做同样的一件事情: 通过添加额外专门的标>签,让HTML更加强大。这些标签实际上被解析为Javascript。我们最终非常舒服的将JS和HTML以此方式混合, 是时候介绍React,以及事情的另一面......
React的JSX不是激进演变。它只是简单的认知成果: 作为一个行业,我们已经确定(有共识):-
HTML和Javascript是胞兄胞弟。
诚然,我们只是没有大声说出来而已。但是对Angular, Knockout和Ember的拥抱,让我们新的偏好更明确。上面已经确定,在HTML中写入数据绑定是一种有效的将JS注入HTML的方式。但是我们要混合,
为什么选择加强一个像HTML一样软弱涣散的技术呢。浏览器从出现的时候就松散的解析HTML。那么HTML是声明数据绑定,循环以及条件逻辑的逻辑基础吗?
Facebook认为Javascript是更加合适的处理这两种混合关系的逻辑和强大技术。 真谛在于(Facebook recognized that JavaScript was a more logical and powerful technology for handling these two intermingled concerns. The epiphany comes down to this):
Angular, Ember和Knockout是在HTML中放置JS。
而React是将HTML放置在JS中。
此举优势有多处,你还没有尝试React和JSX的话可能不会完全意识到。React的JSX在下面几个原因下比阶段2中所有类型的框架更优胜:
如果你在HTML中打错字,一般来说你不知道哪里出了问题。很多情况下都是客户端运行时错误。例如,在使用angular的时候,如果将ng-repeat错误打成n-repeat,不会发生任何事情。同样对于Knockout来说如果将data-bind错误输入为data-bnd也是一样的。这两种情况,应用都会在运行时悄无声息的失败。那是相当沮丧的(frustrating)。
与此相比,在JSX中如果打印错误,根本不会编译。忘记闭合<li>标签? 你是否乐意在你HTML中打印错误的时候获得丰富的反馈呢?
ReactifyError: /components/header.js: Parse Error: Line 23: Expected corresponding JSX closing tag for li while parsing file: /components/header.js
使用JSX, 这种详细的反馈最终成为现实!很难过分强调(overemphasize)这点上面到底优胜多少。这种快速反馈循环极大提高了生产力。正如在我的整洁代码课程中讨论的,精心设计的解决方案失败快
速(well-engineered solutions fail fast)。
在Javascript中组成标签,意味着在使用标签的时候可以尽情享受所有Javascript的强大能力,而不是那些HTML为中心的框架,例如Angular和Knockout, 所提供的少量特殊子集所提供的能力。
客户端框架不应该需要用户学习声明循环和条件语句的专属语法。
React避免学习另外一种专属声明循环和条件语句方式的开销。正如你在阶段2中所见到的,每个双向绑定框架都利用自己特殊语法来实现这些。相比而言,JSX看起来几乎和HTML等价,它使用简单的面>相对象Javascript(ol Javascript)来实现诸如条件和循环的。在各自为政的Javascript生态系统中,不需要学历另外一种专属的数据绑定语法显然略胜一筹。(In an ecosystem as fragmented as JavaScript, not having to learn yet another proprietary data binding syntax is a nice win.)
既然标签和相关联的javascript在同一个文件中书写, 很多IDE也会在你引用函数的时候提供一些智能支持。想象一下在面相HTML的框架中,引用函数的时候会有多么频繁的输入错误。
JSX不是激进的思想。它是自然进化过程的产物。因此尽量不要抓狂。
JSX不是革命,而是进化。
JSX isn’t revolutionary. It’s evolutionary.
正如多数的进化形式,它是一种明智的改进。
是否想要了解更多? 那么请进入我的新课程, 基于pluralsight.com网站上面的(多元视角)"使用React和Flux构建应用程序"
Check out my new course “Building Applications with React and Flux” on Pluralsight.