JavaScript 文件引用编辑本段回目录



JavaScript 程序应该尽量放在 .js 的文件中,需要调用的时候在 HTML 中以 <script src="filename.js"> 的形式包含进来。JavaScript 代码若不是该 HTML 文件所专用的,则应尽量避免在 HTML 文件中直接编写 JavaScript 代码。因为这样会大大增加 HTML 文件的大小,无益于代码的压缩和缓存的使用。另外,<script src="filename.js"> 标签应尽量放在文件的后面。这样会降低因加载 JavaScript 代码而影响页面中其它组件的加载时间。




代码排版编辑本段回目录


行长度



每行代码应小于 80 个字符。如果代码较长,应尽量选择换行,下一行代码应缩进8 个空格。这样可以使代码排版整齐,减轻阅读代码的疲劳感。换行缩进 8 个空格可以和代码段的缩进 4 个空格区分开,以增强代码的可阅读性。



行结束



JavaScript 语句应该以分号结束。但大多数浏览器允许不写分号,只要在本应是分号的地方有一个换行符就行。但是如果代码行较长需要换行的时候,有哪些注意事项呢?换行应选择在操作符和标点符号之后,最好是在逗号','之后,而不要在变量名、字符串、数字、或')' ']' '++' '--'等符号之后换行。这样可以有效的防止拷贝、粘贴而引起的错误,并可有效地增强代码的可阅读性。



缩进



用 4 个空格来进行缩进,将编辑器里的 TAB 快捷键重新设置为 4 个空格。据了解 Eclipse, Vi, Nodepad++,Editplus, UltraEdit 等流行的编辑器,均提供了此功能。 



空行



使用空行来划分一组逻辑上相关联的代码片段


标识符命名编辑本段回目录


  1. 变量、参数、成员变量、函数等名称均以小写字母开头
  2. 构造器的名称以大写字母开头。
  3. 常量及全局变量采用全部大写的形式,单词间用下划线分隔。例如DEFAULT_FRAME_LAYOUT
  4. 下划线'_'开头的变量一般习惯于标识私有 / 局部成员。而美元符号'$'开头的变量习惯于标识系统相关,比如系统进程等。应避免用下划线'_'或美元符号'$'来命名标识符。尽可能地降低代码的阅读负担。
  5. 函数名尽量采用 “动词+名词”的命名方式
  6. 函数名称中的动词前缀必须是和函数功能相关的完整动词
  7. 函数名称的第一个单词全部小写,后面的单词首字母大写,例:getUserName()


声明编辑本段回目录


变量的声明



在函数的开始应先用 var 关键字声明函数中要使用的局部变量,注释变量的功能及代表的含义,且应以字母顺序排序。每个变量单独占一行,以便添加注释。这是因为 JavaScript 中只有函数的 {} 表明作用域,用 var 关键字声明的局部变量只在函数内有效,而未经 var 声明的变量则被视为全局变量。声明变量必须加上 var

函数的声明

函数也应在调用前进行声明,内部函数应在 var 声明内部变量的语句之后声明,可以清晰地表明内部变量和内部函数的作用域。此外,函数名紧接左括号'('之间,而右括号')'和后面的'{'之间要有个空格,以清楚地显示函数名以其参数部分,和函数体的开始。若函数为匿名 / 无名函数,则 function 关键字和左括号'('之间要留空格,否则可能误认为该函数的函数名为 function。不要在语句块内声明函数。



常量的声明



常量的使用包括但不仅限于以下场景:

  1. URLs  - 可能会变动的url
  2. Settings - 全局或局部的配置信息
  3. Repeated strings -  多次使用的字符串


语句编辑本段回目录


对于简单语句而言,需要提及的仍然是分号必要性,同时,一行最多有一个语句。如果一个赋值语句是用函数和对象来赋值,可能需要跨多行,一定切记要在赋值语句末加上分号。这是因为 JavaScript 中,所有表达式都可以当语句,遇换行符时会解析为表达式的结束,此时不规范的换行和分号的丢失,可能引入新的错误。对于复合语句,if, for, while, do, switch, try … catch 等代码体,函数定义的函数体,对象的定义等都需要放在花括号'{}'里面。

  1. '{' 应在行末,标志代码块的开始。
  2. '}' 应在一行开头,标志代码块的结束,同时需要和'{'所在行的开始对齐,以表明一个完整的复合语句段。这样可以极大地提高代码的可阅读性,控制逻辑能清晰地表现出来。
  3. 被包含的代码段应该再缩进 4 个空格。
  4. 即使被包含的代码段只有一句,也应该用花括号'{}'包含。尽管不用花括号代码也不会错,但如若需要增加语句的话,则较容易因花括号遗漏而引起的编译错误或逻辑错误。

return语句在使用时也需慎重,如果用表达式的执行作为返回值,请把表达式和 return 放在同一行中,以免换行符被误解析为语句的结束而引起返回错误。return 关键字后若没有返回表达式,则返回 undefined。构造器的默认返回值为 this。


特殊符号编辑本段回目录


空白符



适当的空白行可以大大提高代码的可阅读性,可以使代码逻辑更清晰易懂。同时,在表达式中适当的留空白,也会给代码的阅读带来方便。

关键字的后面如有括号,则最好在关键字和左括号'('之间留空白,如 for, if, while 等。而函数名和括号之间则不宜留空白,但若是匿名函数,则必须在 function 和左括号'('之间留空白,否则,编辑器会误认为函数名为 function。

在表达式中,二元运算符 ( 除左括号'(',左方括号'[',作用域点'.') 和两个操作数之间最好留空白。一元运算符(若不是词 typeof 等)和其操作数之间不宜留空白。

逗号','的后面需要留空白,以显示明确的参数间隔,变量间隔等。

分号';'之后通常表明表达语句的结束,而应空行。在 for 的条件语句中,分号之后则应该留空白。



{ } 和 [ ]



使用{}和[]定义空对象和空数组



== 和 ===



使用'==='来进行逻辑等的判断,用'!=='进行逻辑不等的判断。永远不要使用==和!=。



'和"



优先使用单引号 (‘) 
当你创建一个包含 HTML 代码的字符串时就知道它的好处了.


注释编辑本段回目录



顶层/文件注释



顶层注释用于告诉不熟悉这段代码的读者这个文件中包含哪些东西.应该提供文件的大体内容, 它的作者, 依赖关系和兼容性信息. 如下:



// Copyright © 2009 - 2011 DBank网盘 All Rights Reserved

/**
 * @fileoverview Description of file, its uses and information
 * about its dependencies.
 * @author user@google.com (Firstname Lastname)
 */





类注释



每个类的定义都要附带一份注释, 描述类的功能和用法.



也需要说明构造器参数.



如果该类继承自其它类, 应该使用 @extends 标记.



如果该类是对接口的实现, 应该使用 @implements 标记.



/**
 * Class making something fun and easy.
 * @param {string} arg1 An argument that makes this more interesting.
 * @param {Array.<number>} arg2 List of numbers to be processed.
 * @constructor
 * @extends {goog.Disposable}
 */
project.MyClass = function(arg1, arg2) {
  // ...
};
goog.inherits(project.MyClass, goog.Disposable);





方法与函数的注释



提供参数的说明. 使用完整的句子, 并用第三人称来书写方法说明.



/**
 * Converts text to some completely different text.
 * @param {string} arg1 An argument that makes this more interesting.
 * @return {string} Some return value.
 */
project.MyClass.prototype.someMethod = function(arg1) {
  // ...
};

/**
 * Operates on an instance of MyClass and returns something.
 * @param {project.MyClass} obj Instance of MyClass which leads to a long
 *     comment that needs to be wrapped to two lines.
 * @return {boolean} Whether something occured.
 */
function PR_someMethod(obj) {
  // ...
}



对于一些简单的, 不带参数的 getters, 说明可以忽略.



/**
 * @return {Element} The element for the component.
 */
goog.ui.Component.prototype.getElement = function() {
  return this.element_;
};





属性注释



也需要对属性进行注释.



/**
 * Maximum number of things per pane.
 * @type {number}
 */
project.MyClass.prototype.someProperty = 4;





JSDoc 缩进



如果你在 @param,



@return, @supported, @this 或



@deprecated 中断行, 需要像在代码中一样, 使用4个空格作为一个缩进层次.



/**
 * Illustrates line wrapping for long param/return descriptions.
 * @param {string} foo This is a param with a description too long to fit in
 *     one line.
 * @return {number} This returns something that has a description too long to
 *     fit in one line.
 */
project.MyClass.prototype.method = function(foo) {
  return 5;
};



jsdoc jsdoc3






Javascript小技巧编辑本段回目录



布尔表达式



下面的布尔表达式都返回 false:



  1. null
  2. undefined
  3. '' 空字符串
  4. 0 数字0
  5. NaN
  6. false



true:



  1. '0' 字符串0
  2. [] 空数组
  3. {} 空对象



下面段比较糟糕的代码:



while (x != null) {



你可以直接写成下面的形式(只要你希望 x 不是 0 和空字符串, 和 false):



while (x) {





如果你想检查字符串是否为 null 或空:



if (y != null && y != '') {



但这样会更好:



if (y) {



注意: 还有很多需要注意的地方, 如:



Boolean('0') == true



'0' != true






0 != null



0 == []



0 == false






Boolean(null) == false



null != true



null != false






Boolean(undefined) == false



undefined != true



undefined != false






Boolean([]) == true



[] != true



[] == false






Boolean({}) == true



{} != true



{} != false





条件(三元)操作符 (?:)



三元操作符用于替代下面的代码:






if (val != 0) {
  return foo();
} else {
  return bar();
}



你可以写成:



return val ? foo() : bar();



在生成 HTML 代码时也是很有用的:



var html = '<input type="checkbox"' +
    (isChecked ? ' checked' : '') +
    (isEnabled ? '' : ' disabled') +
    ' name="foo">';





&& 和 ||



二元布尔操作符是可短路的, 只有在必要时才会计算到最后一项.





“||” 被称作为 ‘default’ 操作符, 因为可以这样:



/** @param {*=} opt_win */
function foo(opt_win) {
  var win;
  if (opt_win) {
    win = opt_win;
  } else {
    win = window;
  }
  // ...
}



你可以使用它来简化上面的代码:



/** @param {*=} opt_win */
function foo(opt_win) {
  var win = opt_win || window;
  // ...
}





“&&” 也可简短代码.比如:



if (node) {
  if (node.kids) {
    if (node.kids[index]) {
      foo(node.kids[index]);
    }
  }
}



你可以像这样来使用:



if (node && node.kids && node.kids[index]) {
  foo(node.kids[index]);
}



或者:



var kid = node && node.kids && node.kids[index];
if (kid) {
  foo(kid);
}





使用 join() 来创建字符串



通常是这样使用的:



function listHtml(items) {
  var html = '<div class="foo">';
  for (var i = 0; i < items.length; ++i) {
    if (i > 0) {
      html += ', ';
    }
    html += itemHtml(items[i]);
  }
  html += '</div>';
  return html;
}



但这样在 IE 下非常慢, 可以用下面的方式:



function listHtml(items) {
  var html = [];
  for (var i = 0; i < items.length; ++i) {
    html[i] = itemHtml(items[i]);
  }
  return '<div class="foo">' + html.join(', ') + '</div>';
}



你也可以是用数组作为字符串构造器, 然后通过 myArray.join('') 转换成字符串. 不过由于赋值操作快于数组的



push(), 所以尽量使用赋值操作.





遍历 Node List





Node lists 是通过给节点迭代器加一个过滤器来实现的.



这表示获取他的属性, 如 length 的时间复杂度为 O(n), 通过 length 来遍历整个列表需要 O(n^2).



var paragraphs = document.getElementsByTagName('p');
for (var i = 0; i < paragraphs.length; i++) {
  doSomething(paragraphs[i]);
}



这样做会更好:



var paragraphs = document.getElementsByTagName('p');
for (var i = 0, paragraph; paragraph = paragraphs[i]; i++) {
  doSomething(paragraph);
}



这种方法对所有的 collections 和数组(只要数组不包含 falsy 值) 都适用.





在上面的例子中, 也可以通过 firstChild 和 nextSibling 来遍历孩子节点.



var parentNode = document.getElementById('foo');
for (var child = parentNode.firstChild; child; child = child.nextSibling) {
  doSomething(child);
}





禁止使用的东西编辑本段回目录



  1. 禁止使用with
  2. 禁止使用eval
  3. 禁止使用位运算符
  4. 禁止使用++和--
  5. 禁止使用void
  6. 禁止使用new Number、new String、new Boolean、new Array、new Object
  7. 禁止使用==和!=





Jslint检查编辑本段回目录




所有javascript代码都要经过jslint检查