[TOC]
JavaScript 是网页的第三个主要部件。在网页上适当地应用JavaScript 代码,通过绑定事件和控制整体行为层,能够增强整体的用户和基于浏览器的体验。
随着功能强劲的新浏览器撑起基于浏览器的完整web应用,JavaScript 在近年的流行度爆棚。另外,对Javascript的细致运用为全面操控另外两个部件 -- [HTML 标记](http://coderlmn.github.io/code-standards/#markup)和 [CSS](http://coderlmn.github.io/code-standards/#css) -- 提供了手段。现在,在无需刷新整个页面的情况下,页面结构和页面视觉样式都可以被实时操控。
## JavaScript库
我们开发新应用主要会用到 [jQuery](http://api.jquery.com/),不过我们对原生 JavaScript 和所有现代 javascript 库也具有专业经验。
## 编码总体原则
* 99%的代码必须封装在外部Javascript文件中。这些文件必须在 BODY 标签的尾部引入,让页面的性能最大化。
* 不要依赖于 user-agent 字符串。进行适当的特性检测. (更多信息参见 [深入 HTML5: 检测](http://diveintohtml5.info/detect.html) 和[jQuery 支持文档](http://api.jquery.com/jQuery.support/))
* 不要使用 document.write()。
* 所有布尔变量的命名必须用 "is" 开头
对正条件的测试
~~~
isValid = (test.value >= 4 && test.success);
~~~
* 给变量和函数的命名要有逻辑意义:例如: `popUpWindowForAd` 就比 `myWindow` 好多了。
* 不要人为缩短命名到最小。除了传统的 `for` 循环中的计数器 `i` 等简化的情况,变量命名必须长到有明确意义。
* 文档必须遵循 [NaturalDocs](http://www.naturaldocs.org/documenting.html) 结构。
* 常量或配置变量(例如动画持续时间等)必须放在文件的顶部。
* 尽力编写可通用化的函数,让它接受参数并返回值。这样有利于充分的代码重用,而且一旦与引入及外部脚本配合起来,能在脚本需要修改时减少开销。例如,相比硬编码一个带有窗口大小、选项和url的弹出式窗口,不如编写一个接受大小、url和选项作为变量的函数。
* 给代码添加注释!这会有利于减少在调试Javascript函数上花费的时间。
* 不要把时间浪费在用 `<!-- -->` 给你的内联Javascript加注释上,除非你还在关注 Netscape 4。 :)
* 把你的代码组织成一套 [对象常量/单例](http://kaijaeger.com/articles/the-singleton-design-pattern-in-javascript.html),按照 [模块化模式](http://www.yuiblog.com/blog/2007/06/12/module-pattern/),或做成 [带构造器的对象](http://mckoss.com/jscript/object.htm)。
* 最小化全局变量 - 你创建的全局变量越少越好。一般来说,用于你的应用命名空间,1会是个好的数字。
在描述任何全局变量的时候要明确指认。
~~~
window.globalVar = { ... }
~~~
### 留空
总的来说,使用留空应该遵循源远流长的英语阅读惯例。 例如,每个逗号和冒号(以及适用的分号)后面要空一格,但在括号内部的左侧和右侧都不要加空格。另外,大括号应该总是和他们前面的参数出现在同一行。
来看看下面的 JavaScript for循环的例子...
正确
~~~
for (var i = 0, j = arr.length; i < j; i++) {
// Do something.
}
~~~
不正确
~~~
for ( var i = 0, j = arr.length; i < j; i++ )
{
// Do something.
}
~~~
也不正确
~~~
for(var i=0,j=arr.length;i<j;i++){
// Do something.
}
~~~
### plugins.js 和 script.js
从 H5BP 开始我们看到了两个文件, plugins.js 和 script.js。本节概述这两个文件的基本用法。
#### plugins.js
Plugins.js 的用处是存放网站的所有插件代码。相比链接到很多不同的文件,我们可以把插件代码统一放到这个文件里,从而改善性能。这种用法会有也应该有例外。例如,一个超级大的插件,又只是用在一个很少被访问到的页面上,放在单独的一个下载链接里就会更好,这样只会在目标页面被打开的时候才会被访问。不过,大部分情况下,直接把所有插件的最小化版本粘贴到这里以便访问是靠谱的。
下面就是一个样例文件,包括一个小目录。它可以作为所用到插件的随身指南,包括文档URL,使用它们的思路,诸如此类。
~~~
/* PLUGIN DIRECTORY
本文件中出现的插件 [按出场顺序排序]
1.) Animate Background Position - http://plugins.jquery.com/project/backgroundPosition-Effect
2.) jQuery Easing Plugin - http://gsgd.co.uk/sandbox/jquery/easing/
3.) jQuery Ajax Form plugin - http://jquery.malsup.com/form/#download
4.) jQuery validation plugin (form validation) - http://docs.jquery.com/Plugins/Validation
-password strength
5.) Styled Selects (lightweight) - http://code.google.com/p/lnet/wiki/jQueryStyledSelectOverview
*/
/**
* 1.) Animate Background Position - http://plugins.jquery.com/project/backgroundPosition-Effect
* @author Alexander Farkas
* v. 1.21
*/
(function($) {
if(!document.defaultView || !document.defaultView.getComputedStyle){ // IE6-IE8
//SNIPPED
};
})(jQuery);
/**
* 2.) jQuery Easing Plugin (we're not using jQuery UI as of yet) - http://gsgd.co.uk/sandbox/jquery/easing/
*/
// t: current time, b: begInnIng value, c: change In value, d: duration
jQuery.easing['jswing'] = jQuery.easing['swing'];
jQuery.extend( jQuery.easing,
{
//SNIPPED
});
;(function($) {
$.fn.ajaxSubmit = function(options) {
//SNIPPED
}
})(jQuery);
/*
* jQuery Styled Select Boxes
* version: 1.1 (2009/03/24)
* @requires jQuery v1.2.6 or later
*
* Examples and documentation at: http://code.google.com/p/lnet/wiki/jQueryStyledSelectOverview
*
* Copyright (c) 2008 Lasar Liepins, liepins.org, liepins@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
jQuery.fn.styledSelect = function(settings) {
//SNIPPED
return this;
};
~~~
#### Script.js
Script.js 的用处是存放网站或应用的代码代码。再次说明,这种方式并不总是最佳解决方案,因为更大的团队 和/或 规模更大、功能更多的项目可以得益于将应用代码分解为模块或功能特性相关的文件。不过,对于较小较简单的应用,以及最初的原型开发,把所有工作集中到 scripts.js 还是靠谱的。
下面是一个简化了的例子,用到了 [基于标记的低调全面的DOM-ready执行](http://paulirish.com/2009/markup-based-unobtrusive-comprehensive-dom-ready-execution/) 模式(【译者注】这里的‘低调’原文是Unobtrusive ,是一种将Javascript从HTML结构抽离的设计概念,避免在HTML标签中夹杂一堆onchange、onclick……等属性去挂载Javascript事件,让HTML与Javascript分离,依MVC的原则将功能权责清楚区分,使HTML也变得结构化容易阅读。),看起来会类似于这样:
~~~
/* Name: Demo
Author: Demo King */
/*demo namespace*/
demo = {
common : {
init : function(){
//initialize
},
finalize : function(){
//finalize
},
config : {
prop : "my value",
constant : "42"
}
},
mapping : {
init : function(){
//create a map
},
geolocate : function(){
//geolocation is cool
},
geocode : function(){
//look up an address or landmark
},
drawPolylines : function(){
//draw some lines on a map
},
placeMarker : function(){
//place markers on the map
}
}
}
~~~
## 变量,ID 及 class
所有的 JavaScript 变量必须写成全小写或驼峰法。一个例外是构造器函数,按惯例是首字母大写。所有CSS里的 `id` 和 `class` 声明都必须只用小写。不允许用连接符或下划线。
### 事件代理
在分配低调(unobtrusive)的事件监听器时,通常可接受的做法是把事件监听器直接分派给那些会触发某个结果动作的元素。不过,偶尔也会有多个元素同时符合触发条件,给每个元素都分配事件监听器可能会对性能有负面影响。这种情况下,你就应该改用事件代理了。
从性能角度考虑,jQuery的 [delegate()](http://api.jquery.com/delegate) 优于 [live()](http://api.jquery.com/live)。
### 调试
即使采用了最好的校验器,浏览器的怪异性也会不可避免地产生一些问题。有几个堪称无价之宝的工具可以帮助优化代码的健全性和加载速度。很重要的一点是,你手头准备好了这些工具,不管你主要用来开发的浏览器是哪个。我们推荐先在Firefox和Safari上做开发,然后用Google Chrome和Opera,最后针对IE用条件判断做一些额外的微调。下面列出的是一些有帮助的调试器和速度分析器:
* **Firefox**: [Firebug](http://getfirebug.com/), [Page Speed](http://code.google.com/speed/page-speed/), [YSlow](http://developer.yahoo.com/yslow/)
* **Safari**: [Web Inspector](http://developer.apple.com/safari/library/documentation/AppleApplications/Conceptual/Safari_Developer_Guide/UsingtheWebInspector/UsingtheWebInspector.html)
* **Google Chrome**: [Developer Tools](http://google.com/chrome/intl/en/webmasters-faq.html#tools)
* **Opera**: [Dragonfly](http://opera.com/dragonfly/)
* **Internet Explorer 6-7**: [Developer Toolbar](http://microsoft.com/downloads/details.aspx?familyid=E59C3964-672D-4511-BB3E-2D5E1DB91038)
* **Internet Explorer 8-10**: [Developer Tools](http://msdn.microsoft.com/en-us/library/dd565625(v=VS.85).aspx)
### 优化 JavaScript 的特征
* 编写可维护的代码
* 单变量模式
* Hoisting:把所有变量声明统一放到函数的起始位置 (在后部声明的变量也会被JS视为在头部定义,由此会产生问题)
* 不要扩充内置原型(虽然给Object(), Function()之类的内置原型增加属性和方法很巧妙,但是会破坏可维护性)
* 不要用隐含的类型转换
* 不要用 eval()
* 用 parseInt() 进行数字转换
* (规范)左大括号的位置
* 构造器首字母大写
* 写注释
* 不要用 void
* 不要用 with 语句
* 不要用 continue 语句
* 尽量不要用位运算
Stoyan Stefanov 的博文包含了以上原则 [并有详细说明](http://net.tutsplus.com/tutorials/javascript-ajax/the-essentials-of-writing-high-quality-javascript/)(【译者注】这篇博文值得一看)。