JavaScript 开发最佳实践

2063 查看

写一篇关于最佳实践的文章是十分困难的事情。你们将要读到的内容是显而易见,但是明智的做法。

然而,多年来在网上浏览并查看其他开发者提交的代码的经历告诉我,想要在网络的编程环境中找到一定的常识是几乎不可能的事,并且一旦你身处于一个项目中时,随着 deadline 的步步逼近,“做明智且有逻辑的事”就会在优先级列表中被推得越来越远。

所以,我决定创作这篇文章更简单地让你了解,什么是最佳实践,以及我这么多年积累的优秀建议。其中大部分都来之不易(通过实验等方法得到的)。记住下面给出的建议,让它们成为你大脑的一部分,这是一个快速有效的方法帮助你不用考虑太多就能接受这些建议。我相信你一定会发现与你的想法不一致的地方,这是好事 —— 你应该质疑读到的东西,然后努力找到更好的解决方法。不过,我发现遵循下面这些原则可以使我成为一名更有效率的开发者,也方便了其他开发者在我的工作基础上进行后续开发。

下面是本文的组织结构:

给变量和函数命名 ——变量名和函数名尽量简短且易读

一种很简单但又很可怕的情况是你经常会在 JavaScript 中碰到像 x1fe2 或者 xbqne 的变量名,或者 —— 另一种极端命名 —— 像incrementorForMainLoopWhichSpansFromTenToTwenty 或者createNewMemberIfAgeOverTwentyOneAndMoonIsFull 这样的变量名。

这种命名没有任何意义 —— 好的变量和函数命名应该易于理解,并告知它的作用 —— 不多也不少。还有一个需要避免的陷阱是在命名中将数值与功能结合。由于合法饮酒年龄因国家而异,isLegalDrinkingAge() 就比 isOverEighteen() 更加适合,除了饮酒外,还有其他事情也是一样需要考虑年龄限制的。

匈牙利命名法是一种值得采用的不错的命名方案(还有一些其他的命名方案可以考虑),优势在于你知道应该怎样去命名,而不仅仅知道它是什么名字。

举个例子,如果你有一个名为 familyName 的变量,它是一个字符串,那么根据 “匈牙利命名法” 你应该将其写为 sFamilyName。一个名为 member 的对象可被写为 oMember,一个名为 isLegal 的布尔对象可被写为 bIsLegal。在某些情况下,这种命名信息量很大,但在某些情况下又似乎额外开销太大,这取决于你是否选择使用它。

保持英文也是一个好主意。编程语言都使用英文,所以为何不把这个作为你代码逻辑中的一环呢。调试一段时间的韩语与斯洛文尼亚语代码后,我向你保证这对于一名非母语者来说的确不是一件有趣的事。

把你的代码当成叙事。如果你可以一行一行地阅读并理解它在讲述什么,说明你做的不错。如果你需要使用画板来理清逻辑流程,那么你的代码还需要再优化一下。如果你想要对比一个真实的世界,试着去阅读 Dostojewski(俄国作家)的作品吧 —— 看见写有 14 个俄罗斯名字的一页后,我完全迷茫了,其中有 4 个都是假名。不要写出那样的代码 —— 虽然那样看起来更像艺术而非产品,但并不是一件好事。

避免全局

全局变量和函数名是一个非常糟糕主意。因为页面中的每个 JavaScript 文件都在同一个范围内运行。如果你的代码中有全局变量或者函数,后面脚本中包含的相同变量和函数名将会覆盖你的全局变量或函数。

下面是几个避免使用全局变量的变通方法 —— 现在我们一个个展示它们。如果你有三个函数和一个变量,就像这样:

你可以使用一个对象字面量来保护它们不被重写:

这会起作用,但有一个缺点 —— 调用函数或改变变量值时,你都需要使用主对象的名字:init()myNameSpace.init()currentmyNameSpace.current 等等。这很讨厌并重复。

但我们可以简单地使用一个匿名函数包含所有事物并通过这种方式保护此域。同样意味着你不需将语法从 function name() 转换为 name:function()。这个特性被称为模块化开发:

继续,这样改进仍有问题。这些方法与变量对于外界来说都不再可用。如果你想让它们可用,需要在一个 return 代码块里包含你想要让其变成 public 的事物:

在链接两个方法和改变语法方面,这几乎把我们带回了起点。因此我更喜欢像下面一样(我赋予其“展示性模块化”称号):