《编写可维护的JavaScript》读书笔记

515 阅读5分钟

第二部分 编程实践

构建软件设计的方法有两种:一种是把软件做的很简单以至于明显找不到缺陷;另一种是把它做的很复杂以至于找不到明显的缺陷。 ----C.A.R.Hoare, 1980年图灵奖获得者

在本书的第一部分里,我们主要讨论JavaScript的代码风格规范。代码风格规范的目的是在多人写作的场景下使代码具有一致性。关于如何解决一般性问题的讨论是不包含在风格规范中的,那是编程实践中的内容。

第5章 UI层的松耦合

在web开发中,用户界面是由三个彼此隔离又相互作用的层定义的:

  • HTML用来定义页面的数据和语义
  • CSS用来给页面添加样式,创建视觉特征
  • JavaScript用来给页面添加行为,使其更具交互性

为了更多地增加分层的合理性和消除依赖性,我们认为在所有Web UI中,CSS和JavaScript是同等重要的。比如:JavaScript的正确运行不应当依赖CSS——在缺少CSS的情况下也要能够正确运行,尽管两者之间可能有些互动。

5.1 什么是松耦合

很多设计模式就是为了解决紧耦合的问题。如果两个组件耦合太紧,说明一个组件和另一个组件直接相关,这样的话,如果修改一个组件的逻辑,那么另外一个组件的逻辑也要修改。

当你能够做到修改一个组件而不需要更改其他的组件时,你就做到了松耦合。对于多人大型系统来说,有很多人参与维护代码,松耦合对于代码可维护性来说至关重要。你绝对希望开发人员在修改某部分代码时不会破坏其他人的代码。

有一点需要注意:在一起工作的组件无法达到“无耦合”。在所有系统中,组件之间总要共享一些信息来完成各自的工作。这很好理解,我们的目标是确保对一个组件的修改不会经常性的影响其他部分。

5.2 将JavaScript从CSS中抽离

在IE8和更早版本的浏览器中有一个特性让人爱少恨多,即CSS表达式。

// 不好的写法
.box{
    width: expression(document.body.offsetWidth + 'px');
}

CSS表达式包裹在一个特殊的expression()函数中,可以给它传入任意JavaScript代码。浏览器会以高频率重复计算CSS表达式,这严重影响了性能。

除了性能问题,在CSS中嵌入JavaScript代码对于代码维护来说亦是一场噩梦。作者曾花了一整天时间在JavaScript中查找脚本错误,罪魁祸首竟然是CSS。

幸运的是,IE9不再支持CSS表达式了,但是老版本的IE依然可以运行CSS表达式。尽管我们很少用CSS表达式去实现一些罕见的功能,来让低版本浏览器里也达到了和高级浏览器一致的表现,但还是要克制住这份冲动,避免不必要地浪费时间和精力。

5.3 将CSS从JavaScript中抽离

有时候,保持CSS和JavaScript之间清晰的分离是很有挑战的。这两门语言相互协作得不错,所以我们经常将样式数据和JavaScript混写在一起。通过脚本修改样式最流行的一种方法是,直接修改DOM元素的style属性。

// 不好的写法
element.style.color = "red";

这种方法是有问题的,因为样式信息是通过JavaScript而非CSS来承载的。当出现了样式问题,你通常会先去查找CSS,直到你精疲力尽地排除了所有可能性,才会去JavaScript中查找样式信息。

开发者修改style对象还有一种方式,给cssText属性赋值整个CSS字符串,看下面这个例子:

// 不好的写法
element.style.cssText = "color: red; left: 10px; top: 100px; vidibility: hidden";

使用cssText属性只是一次性设置多个CSS属性的一种快捷写法。这种模式同样有问题,比如在设置单个属性时:将样式信息写入JavaScript带来了可维护性问题。

将CSS从JavaScript中抽离意味着所有的样式信息都勇当保持在CSS中。当需要通过JavaScript来修改元素样式的时候,最佳方法是操作CSS的className。

5.4 将JavaScript从HTML中抽离

很多人学习JavaScript之初所做的第一件事是,将脚本嵌入到HTML中来运行。有很多种方式。第一种方式是使用on属性(比如onclick)来绑定一个事件处理程序。

// 不好的写法
<button onclick="dosomething()" id="action-btn"></button>

这种写法在2000年的时候非常流行,多数网站都采用了这种写法。HTML代码中放满了onclick和其他的事件处理程序,很多元素都包含这样的属性。尽管这种代码在多数场景下是正常工作的,但却是两个UI层(HTML和JavaScript)的深耦合,因此这种写法是有一些问题的。

首先,当按钮上发生点击事件时,doSomething()函数必须存在。

第二个问题在于可维护性方面。如果你修改了doSomething()的函数名,你需要同时修改JavaScript和HTML代码。这就是典型的紧耦合代码。

你的绝大多数(并非所有的)JavaScript代码都应当包含在外部文件中,并在页面中通过<script>标签来引用。在HTML代码中,也不应当直接给on属性挂载事件处理程序。相反,一旦外部脚本文件加载至页面,则使用JavaScript方法来添加事件处理程序。

5.5 将HTML从JavaScript中抽离

在JavaScript中使用HTML的情形往往是给innerHTML属性赋值时,比如:

// 不好的写法
var div = document.getElementById("my-div");
div.innerHTML = "<h3>Error</h3><p>Invalid e-mail address.</p>";

将HTML嵌入在JavaScript代码中是非常不好的实践。原因有几个:第一,增加了跟踪文本和结构性问题的复杂度,第二,不利于代码维护。