原文:The Design of Code: Organizing JavaScript
作者:Anthony Colangelo
译者:@涂鸦码龙
伟大的设计是一个产品应该关注和重视的点,这样才能造就一个可用的,好理解的,精美的用户界面。千万不要认为设计仅仅是设计师的事。
代码里面有好多种设计,我不是指代码构建了用户界面——我是指代码的设计。
精心设计的代码更易于维护,优化和扩展,能使开发者更高效。这意味着更多的注意力和精力可以花在构建伟大的事情上,每个人都很愉快——用户,开发者和利益相关者。
有3个高级的,跟语言无关的点,对代码设计十分重要。
- 系统架构——代码库的基础设计。控制各种组件的规则,例如模块(models),视图(views)和控制器(controllers),以及之间的相互作用。
- 可维护性——如何更好地改进和扩展代码?
- 复用性——应用组件如何复用?每个组件的实例如何简便地个性定制?
比较宽松的语言,特别是 JavaScript ,需要一些规矩才能写好——代码设计。JavaScript 环境非常宽松,随处扔些代码片段,就可能起作用。早点确立系统架构(然后遵守它!)对你的代码库提供制约,确保自始至终的一致性。
我比较喜欢的一个方法由久经考验的软件设计模式组成——模块模式,可扩展的结构使它成为可靠的系统架构,和可维护的代码库。我喜欢在一个 jQuery 插件里面构建模块,有漂亮的复用性,提供强健的选项设置,暴露一些精心设计的 API。
下面,我将逐步讲解如何精心设计你的代码,把它变成结构良好的组件,从而在项目中复用。
模块模式
已有许多设计模式,同样有许多相关资源。Addy Osmani 写了本关于 JavaScript 设计模式的书《令人惊奇的书(免费!)》,我极力推荐给各个水平的开发者。
模块模式 是一个简单的结构基础,它可以让你的代码保持干净和条例清晰。一个“模块”就是个标准的包含方法和属性的对象字面量,简单是这个模式的最大亮点:甚至一些不熟悉传统的软件设计模式的人,一看就能立刻明白代码是如何工作的。
用此模式的应用,每个组件有它独立的模块。例如,创建自动完成功能,你要写个模块用于文本区域,一个模块用于结果列表。两个模块相互工作,但是文本区域代码不会触及结果列表代码,反之亦然。
模块解耦是模块模式非常适于构建可靠的系统架构的原因。应用间的关系是明确定义的;任何关系到文本区域的事情被文本区域模块管理,并不是散落在代码库中——代码整洁。
模块化组织的另一个好处是固有的可维护性。模块可以独立地改进和优化,不会影响应用的任何其它部分。
我的 jPanelMenu 用到了模块模式,我创建此 jQuery 插件用于关闭画布(off-canvas)的菜单系统。我将用这个例子演示创建模块的过程。
创建一个模块
首先,我定义三个方法和一个属性,用于管理菜单系统的交互。
|
|
这个想法把代码拆分到最小能复用的程度。我还可以写成一个 toggleMenu( )
方法,但是创建单独的 openMenu( )
和 closeMenu( )
更利于模块间的复用。
注意到模块方法和属性的调用(例如 setMenuStyle( )
调用),用到了 this
关键字——模块通过它访问自己的成员。
这是模块的基础结构。你可以继续添加需要的方法和属性,一点也不复杂。在基础结构就位后,复用层——选项和暴露 API ——可以在此基础上创建。
jQuery 插件
精心设计的第三方代码最关键的是:复用性。用原生的 JavaScript 同样可以实现重用组件,我更喜欢用 jQuery 插件做更复杂的事情,有以下几个原因。
最重要的是,它是一个不显眼的沟通形式。如果你用 jQuery 创建一个组件,具体实现非常明确。构建一个组件作为 jQuery 插件等于说 jQuery 是必须的。
此外,实现代码将与其余的基于 jQuery 的项目代码保持一致,意思是开发者不需要太多研究就可以学会与插件的交互。
在你开始创建 jQuery 插件前,确保插件没有跟其他用 $
符号的 JavaScript 库冲突。非常简单——像这样包裹你的插件代码:
|
|
下一步,我们设置插件,并把先前的模块代码放到里面。一个插件仅仅是定义在 jQuery ($)
对象上的一个方法。
|
|
使用插件时调用你创建的函数即可。
|
|
选项设置
选项设置是任何可复用的插件所必须的,因为它允许自定义。每一个项目都带来了一系列的设计风格、交互类型和内容结构。自定义选项帮助插件去适应项目的约束。
最佳实践是为选项提供合适的默认值。最容易的方式是用 jQuery 的 $.extend( ) 方法,它接收(至少)两个参数。
$.extend( ) 的第一个参数,定义一个对象包含所有可用的选项,以及默认值。第二个参数传入选项。它将合并两个对象,传入选项时会覆盖默认值。
|
|
除了提供默认值,选项几乎可以自我说明——人们看代码时立刻看到了所有可用的选项。
暴露尽可能多的选项是可行的,将有助于在未来实现定制和灵活性。
API
选项是自定义插件的好方法。另一方面, API 通过暴露属性和方法,启用扩展插件的功能。
尽可能通过 API 暴露,外部不应该直接访问到所有内部的方法和属性。理想情况下,你应该仅公开使用的元素。
我们的例子,暴露的 API 应该包含打开和关闭菜单,仅此而已。内部的 setMenuStyle( )
方法在菜单打开和关闭的时候运行,但是全局不需要访问它。
为了公开 API,在插件代码最后,返回一个带有期望的方法和属性的对象。甚至可以把返回的属性和方法放到模块代码中——这是模块模式漂亮的组织形式的真正亮点。
|
|
通过对象的返回及插件的初始化,API 方法和属性将变得可用。
|
|
打磨开发者接口
通过几个简单的步骤和指导,我们已经构建了可复用,可扩展的插件。实验一下这一架构是否适合你,你的团队,以及你的工作流程。