Google JavaScript代碼風格指南

Google JavaScript代碼風格指南javascript

修正版本 2.28php

Aaron Whyte
Bob Jervis
Dan Pupius
Eric Arvidsson
Fritz Schneider
Robby Walker
css

每一個風格點都有一個展開/收起按鈕以便你能夠獲得更多的信息:▽. 你能夠將所有展開或收起:html

▽ 所有展開/所有收起java

內容樹node

JavaScript語言規範面試

變量 常量 分號 嵌套函數 塊內函數聲明 異常處理 自定義異常 標準特性 基本包裝類型 多級原型結構 方法定義 閉包 eval() with() {} this for-in 循環 關聯數組多行字符串字面量 Array和Object字面量 修改內置對象的原型 IE下的條件註釋正則表達式

JavaScript代碼風格規範express

命名 自定義toString()方法 延遲初始化 明確做用域 代碼格式化 括號 字符串 可見性(私有和受保護的字段) JavaScript 類型 註釋 內部類和枚舉 編譯壓縮 提示和技巧數組

背景

JavaScript是一門客戶端腳本語言,Google常常用它來曬優越,本文檔列出了一些在作JS項目時須要注意的地方。都是高富帥整理的,還望各位屌絲們有時間都好好看看多學學,別對這個世界太消極了!(譯者注:所謂的客戶端呢就是瀏覽器或本地軟件環境,市面上全部的瀏覽器都支持JS,JS發展到如今統一WEB端再進軍移動互聯網後,相信在一段時間內都是不可被輕易替代的語言,因此有興趣的同窗們能夠多關注一下)

JavaScript語言規範

變量(var

原文

每一個變量聲明都要加上var關鍵字噢。

解釋:若是你不指定關鍵字var, 該變量就會暴露在全局做用域(window)中,這極可能會覆蓋全局做用域中的同名變量,從而引起問題(另外GC也會所以而沒法有效回收內存啊),因此務必用var聲明變量。

常量

原文

常量命名用相似NAMES_LIKE_THIS這樣的形式。沒事幹了能夠用@const來標記它是常量,但永遠不要用const關鍵字來進行常量聲明。

解釋:

對於基本類型的常量,命名簡介解釋一下做用就能夠了。

/**

* 一分鐘有多少秒呀

* @type {number}

*/

goog.example.SECONDS_IN_A_MINUTE = 60;

對於非基本類型,用@const註釋一下會更明瞭。

/**

* 已知單位所對應的秒數

* @type {Object.<number>}

* @const

*/

goog.example.SECONDS_TABLE = {

minute: 60,

hour: 60 * 60

day: 60 * 60 * 24

}

這個標記主要是讓編譯器知道這變量是常量狀態。

至於關鍵詞const,IE不解析啊會報錯的,因此別用啦。

分號

原文▽每一語句的結尾都要加上分號噢。

若是不加分號JS解釋器也會按隱式分隔的標準去執行,但那樣調試、壓縮、合併的時候都很不方便。不要那樣作嘛你能夠作的更好的不是麼。

並且在某些狀況下,不寫分號但是很危險的:

// 1.

MyClass.prototype.myMethod = function() {

return 42;

} // 這個缺德的沒寫分號

(function() {

// 匿名函數的執行

})();

var x = {

'i': 1,

'j': 2

} // 這個天殺的也沒寫分號

// 2. 在IE和FF的某些版本里試試(譯者表示沒試出來)

// 老子知道你永遠也不會寫這樣2的代碼的,但它真的會由於木有寫分號而報錯噢

[normalVersion, ffVersion][isIE]();

var THINGS_TO_EAT = [apples, oysters, sprayOnCheese] // 這個屌絲木有寫分號

// 3. conditional execution a la bash

-1 == resultOfOperation() || die();

上段代碼會發生什麼事情?

  1. 會報錯(number is not a function)-第一個方法返回了42,由於沒分號啊,後面就直接跟括號,因此第二個方法就很杯具的被當成一個參數傳進來給42執行了(效果等同於"42(func)()"),可42並非一個方法,報錯。
  2. 在運行時可能會報 'no such property in undefined' 這樣的錯誤,效果等同因而執行 x[ffVersion][isIE]()。(譯者木驗證)
  3. 若是 resultOfOperation() 返回非 NaN 那就會調用 die 方法,並致使 die() 執行後的返回結果會賦給 THINGS_TO_EAT 。

爲啥會這樣呢?

JS語句以分號做爲結束符使得JS解釋器解析,若是省略分號,就會由JS解釋器肯定語句的結尾。尼瑪,不是在很明確的狀況下,它能肯定麼?上面幾個例子裏,都是在語句中聲明瞭/函數/對象/數組,但閉括號("}"或"]")並不表明着結束。若是下一個語句開始是一箇中綴或括號運算符,那JS就永遠不會結束聲明。

這真的是很奇怪的事情噢親,並且真的不知道還會出現什麼奇怪的事情噢親,因此確保你的語句有分號結束吧。

譯者注:加上分號也會在某些狀況下增進代碼的性能,由於這樣解析器就沒必要再花時間推測應該在哪裏插入分號了(取自《Javascript高級程序設計》)

嵌套函數

原文▽可使用,木有問題。

嵌套函數很是有用,它能夠重用而減小代碼量,或防止一些輔助做用的方法暴露在外等優勢,請隨意把玩(叫破喉嚨也不會有人來救它的)。

塊內函數聲明

原文▽呀咩嗲。

只有屌絲才這樣作:

if (x) {

function foo() {}

}

雖然大多數JS引擎都支持塊內聲明函數,但它並非 ECMAScript 標準的一部分(詳見 ECMA-262, 第13條和第14條)。更糟糕的是各引擎對於塊內函數聲明的實現都不同,和 EcmaScript 的建議相違背。 ECMAScript 只容許在根腳本語句或其餘函數中進行函數聲明,若是必定要用的話能夠在塊內用變量來定義函數:

if (x) {

var foo = function() {}

}

異常處理

原文▽支持合理使用。

無論誰寫代碼都不能百分百的說本身的程序木有異常的。因此,細心的檢查代碼是一方面,預先處理一些可能出現的異常也是有必要的(使用try-catch(e)),特別是正在作一些重要項目的時候(框架什麼的)。

譯者注:若是是預先就知道本身的代碼會發生錯誤時,再使用try-catch語句就不合適了噢,而是應該預先對其進行檢查,防止錯誤的出現(取自《JavaScript高級程序設計》)

自定義異常

原文▽支持合理使用。

沒有自定義異常拋出的狀況下,代碼運行可能會報一些原始的錯誤信息,但包含的內容和錯誤描述會因瀏覽器而不一樣卻都不是特別明確,不易維護,No fashion!因此在感受適當的時候可使用自定義異常拋出(這裏指的是throw,帶有適當信息的自定義錯誤可以顯著提高代碼的可維護性)。

標準特性

原文▽老是優越於非標準特性之上。

爲了得到最大的可移植性和兼容性,儘可能依賴於標準方法。(好比使用 string.charAt(3) 而不是 string[3] ,再好比經過DOM原生方法去訪問節點元素,而不是使用某框架封裝好的獲取方法或快捷引用)。

基本包裝類型

原文▽主動 new 基本包裝類型(Boolean/Number/String)的人兒永遠也成不了高富帥!

木有必要去使用基本包裝類型麼就不要使用啦,並且它在如下這種狀況下很危險:

var x = new Boolean(false);

if (x) {

alert('hi'); // 顯示 hi。由於基本包裝類型的實例調用typeof會返回"object",對象麼在判斷時都會被轉換爲布爾值true。

}

因此,你懂得!就算不懂,也終有一天會懂的嘛!

唉,但是仍是有種狀況是可使用的嘛,好比類型轉換:

var x = Boolean(0);

if (x) {

alert('hi'); // 不會彈框顯示 hi

}

typeof Boolean(0) == 'boolean';

typeof new Boolean(0) == 'object';

它對於 number, string 和 boolean 之間的類型轉換頗有幫助。

多級原型結構

原文

不是怎麼推薦使用。

多級原型結構指的是 JavaScript 實現繼承。 好比自定義類D,並把自定義類B做爲D的原型,那就是一個多級原型結構了。怎麼說呢,結構愈來愈複雜了就越難維護。

鑑於此,使用 the Closure Library 的 goog.inherits() 或許會是更好的選擇。

function D() {

goog.base(this)

}

goog.inherits(D, B);

D.prototype.method = function() {

...

};

方法定義

原文

Foo.prototype.bar = function() { ... };

給原型對象的構造函數添加方法和屬性有不少種方式,更傾向於使用如下這種風格:

Foo.prototype.bar = function() {

/* ... */

};

閉包

原文

上古之大殺器,順則飛龍在天,濫則亢龍有悔。

頗有用,卻常常被忽略(哪裏被忽略了基本哪次面試都有被問到這樣的問題有木有!!!)。有耐心的去看看 a good description of how closures work

有一件須要注意的事情,閉包會保持一個指向它封閉做用域的指針,因此在給DOM元素附加閉包時,極可能會產生循環引用,進一步的消耗內存,好比下面的代碼:

function foo(element, a, b) {

element.onclick = function() { /* uses a and b */ };

}

即使這個閉包函數內部並無使用 element,可它仍是保持了對 element, a 和 b 的引用,而 element 也保持了對這閉包函數的引用,就致使了循環引用,沒法被GC回收。若是遇到了這種狀況,能夠將代碼優化一下:

function foo(element, a, b) {

element.onclick = bar(a, b);

}

function bar(a, b) {

return function() { /* uses a and b */ }

}

譯者注:因爲IE9以前的版本對JScript對象和COM對象使用不一樣的垃圾收集例程,所以閉包在IE的這些版本中會致使如上問題。這個匿名函數做爲element元素事件處理程序,造成閉包的狀態就會保存對父層函數內活動對象的引用,只要匿名函數存在,element的引用數至少也是1,所以它所佔用的內存就永遠不會被回收。注意,閉包會引用包含函數的整個活動對象,即便閉包不直接引用element,包含函數的活動對象中也仍然會保存一個引用。所以,有必要把使用完的element變量設置爲null,解除對DOM對象的引用,確保正常回收其佔用的內存。(取自《Javascript高級程序設計》184P)

eval()

原文

只用於反序列化。(反序列化的意思是從字節流中重構對象,這裏指的應該是JSON字符串重構成對象,或是執行服務器返回的JS語句)

eval() 很不穩定,會形成語義混亂,若是代碼裏還包含用戶輸入的話就更危險了,由於你沒法確切得知用戶會輸入什麼!難道就不能用更好更清晰更安全的方式去寫你的代碼麼孩子?

然而 eval 很容易解析被序列化的對象,因此反序列化的任務仍是能夠交給它作的。(例如:解析RPC響應的時候)

反序列化的過程就是將字節流轉換成內存中的數據結構。例如,你可能會將對象輸出到文件中:

users = [

{

name: 'Eric',

id: 37824,

email: 'jellyvore@myway.com'

},

{

name: 'xtof',

id: 31337,

email: 'b4d455h4x0r@google.com'

},

...

];

用 eval 能夠很簡單的讀取這些數據到內存中。

一樣,用 eval() 能夠簡單的解碼RPC返回值。例如,你用 XMLHttpRequest 發出一個RPC請求,服務器端相應返回JavaScript代碼:

var userOnline = false;

var user = 'nusrat';

var xmlhttp = new XMLHttpRequest();

xmlhttp.open('GET', 'http://chat.google.com/isUserOnline?user=' + user, false);

xmlhttp.send('');

// Server returns:

// userOnline = true;

if (xmlhttp.status == 200) {

eval(xmlhttp.responseText);

}

// userOnline is now true.

with() {}

原文▽別用。

使用 with 語句會讓你的代碼行如踏雲,毫無安全感。由於用 with 添加過來的對象可能會對當前局部做用域的屬性與方法產生衝突,進而影響到整個環境。好比,下面的代碼發生了什麼:

with (foo) {

var x = 3;

return x;

}

回答: 啥事均可能發生。這個局部變量 x 可能會被 foo 對象裏的屬性所覆蓋,它甚至可能會有setter,致使在賦值3時會執行許多其餘的代碼,因此太危險了,別用 with 。

this

原文

僅在構造函數,方法,閉包中去使用它。

this 語義很特別。它大多數狀況下會指向全局對象,有的時候倒是指向調用函數的做用域的(使用eval時),還可能會指向DOM樹的某個節點(綁定事件時),新建立的對象(構造函數中),也多是其餘的一些什麼亂七八糟的玩意(若是函數被 call() 或者被 apply() )。

很容易出錯的,因此最好是如下這兩種狀況的時候再選擇使用:

  • 在構造函數中(原型對象)
  • 在對象的方法中(包括建立的閉包)

for-in 循環

原文

只在 object/map/hash 要遍歷鍵值的時候使用。

對 Array 類型的對象進行 for-in 循環可能會出錯,由於它不是從 0 到 length - 1 ,而是這個對象包括其原型鏈上的全部鍵值,下面是一些失敗的例子:

function printArray(arr) {

for (var key in arr) {

print(arr[key]);

}

}

printArray([0,1,2,3]); // 雖然這沒問題

var a = new Array(10);

printArray(a); // 這就錯了

a = document.getElementsByTagName('*');

printArray(a); // 錯

a = [0,1,2,3];

a.buhu = 'wine';

printArray(a); // 錯的

a = new Array;

a[3] = 3;

printArray(a); // 仍是錯的

遍歷數組一般用for就能夠了。(譯者注:若是木有順序要求,可使用for(var i = l;i--;)速度會更高些,但這是10萬級效率差,一般是能夠被忽略的)

function printArray(arr) {

var l = arr.length;

for (var i = 0; i < l; i++) {

print(arr[i]);

}

}

關聯數組

原文

永遠不要用 Array 去作 map/hash/associative 要作的事情。

不容許使用關聯 Arrays ……更具體的說是不容許使用非數字索引的數組(Array不都是用數字索引的麼,也沒辦法用吧除非是兩個數組同索引)。若是你須要一個map/hash那就用 Object 來代替 Array 吧,實際上你想用的就是 Object 而不是 Array。 Array 只是繼承自 Object (和Date, RegExp 和 String同樣)。

多行字符串字面量

原文▽不要!

不要這樣寫:

var myString = 'A rather long string of English text, an error message \

actually that just keeps going and going -- an error \

message to make the Energizer bunny blush (right through \

those Schwarzenegger shades)! Where was I? Oh yes, \

you\'ve got an error and all the extraneous whitespace is \

just gravy. Have a nice day.';

空白字符開頭字符行不能被很安全的編譯剝離,以致於斜槓後面的空格可能會產生奇怪的錯誤。雖然大多數腳本引擎都支持這個,但它並非ECMAScript標準的一部分。

能夠用+號運算符來鏈接每一行:

var myString = 'A rather long string of English text, an error message ' +

'actually that just keeps going and going -- an error ' +

'message to make the Energizer bunny blush (right through ' +

'those Schwarzenegger shades)! Where was I? Oh yes, ' +

'you\'ve got an error and all the extraneous whitespace is ' +

'just gravy. Have a nice day.';

ArrayObject字面量

原文▽推薦使用。

用 Array 和 Object 字面量代替 Array 和 Object 構造函數。

Array 構造函數會由於傳參不當而致使理解錯誤。

// 長度是 3.

var a1 = new Array(x1, x2, x3);

// 長度是 2.

var a2 = new Array(x1, x2);

// 若是x1是天然數那數組的長度就變成了x1

// 若是x1是數字但不是天然數就會報錯

// 否則數組就會有一個元素x1

var a3 = new Array(x1);

// 長度是 0.

var a4 = new Array();

如上,若是傳入了一個參數而不是兩個,那這數組可能就不是預期的長度了。

爲了不這種狀況,用更可讀的數組字面量吧。

var a = [x1, x2, x3];

var a2 = [x1, x2];

var a3 = [x1];

var a4 = [];

Object 構造函數沒有如上問題,但考慮到可讀性和一致性,用字面量更好些。

var o = new Object();

var o2 = new Object();

o2.a = 0;

o2.b = 1;

o2.c = 2;

o2['strange key'] = 3;

應該寫成:

var o = {};

var o2 = {

a: 0,

b: 1,

c: 2,

'strange key': 3

};

修改內置對象的原型

原文▽別這樣作。

禁止修改 Object.prototype 和 Array.prototype 這樣的內置對象。可能修改 Function.prototype 危險性會小些,但它一樣會在調試中出現問題,因此儘可能避免這樣的狀況吧。

IE下的條件註釋

原文▽別用。

不要這樣作:

var f = function () {

/*@cc_on if (@_jscript) { return 2* @*/ 3; /*@ } @*/

};

條件註釋會妨礙自動化工具的執行,由於他會在運行時改變 JavaScript 語義樹。

JavaScript代碼風格規範

命名

原文

一般,使用相似於 functionNamesLikeThis, variableNamesLikeThis, ClassNamesLikeThis, EnumNamesLikeThis, methodNamesLikeThis, 和 SYMBOLIC_CONSTANTS_LIKE_THIS 這樣的命名方式(駝峯式)

屬性和方法

  • 私有的屬性,變量和方法(在文件或類中)都應該改如下劃線開頭。
  • 受保護的屬性,變量和方法不須要用下劃線(和公開的同樣)。

更多關於 privateprotected 去看 visibility 這一部分吧。

方法和函數參數

可選參數以 opt_ 開頭。

函數參數不固定的時候應該有個參數 var_args 以數組的形式將參數傳進來,也許你不喜歡這樣作,那你可使用 arguments 這個僞數組。

可選和可變參數都應該用 @param 註釋標記一下,雖然對解釋器都沒什麼影響,但仍是儘可能遵照吧,以讓代碼可以更易理解。

屬性的訪問器

EcmaScript 5 不推薦使用對象屬性的 getters 和 setters。你用了就用了吧,可是你得注意,千萬別讓 getters 方法改變當前對象的各屬性狀態。

/**

* 錯 -- 不要這樣作

*/

var foo = { get next() { return this.nextId++; } };

};

函數的訪問器

函數對象中的 Getters 和 Setters 也不是必須的。但若是你用了,你最好以相似 getFoo() 和 setFoo(value).的形式來命名。(若是返回布爾型的值,能夠用 isFoo() 或者其餘更天然的名字)

命名空間

JavaScript並不支持包和命名空間。

這樣就致使JS在兩個項目以上的集成環境中可能會出現全局做用域下的命名衝突,後果嚴重且不易調試。爲了提升代碼的公用性,請你們遵照以下約定以免衝突。

在全局做用域下使用僞命名空間

在全局做用域下對相關的JS項目或庫用惟一的頂級變量標識看成僞命名空間。好比你的項目名是"Project Sloth",那能夠寫一個僞命名空間 sloth.*.

var sloth = {};

sloth.sleep = function() {

...

};

好多相似 the Closure Library and Dojo toolkit 這樣的JS庫都會給你一個高階方法來讓你聲明命名空間,而後你就能夠在這個命名空間下進行各類聲明瞭。

goog.provide('sloth');

sloth.sleep = function() {

...

};

明確命名空間全部權

當你選擇了一個子命名空間下進行開發,請告知父命名空間的負責人(你懂得)。假設你開始了一個項目是sloths下的hats,請確保這個Sloth項目的負責人知道是你在用sloth.hats。

外部代碼和內部代碼使用不一樣的命名空間

「外部代碼」指的是你的代碼體系之外的可獨立編譯的代碼,好比你用了一個外部庫在 foo.hats.* 下,那你本身的內部代碼就不該該再在其下面了,不然會致使產生衝突和難以維護。

foo.require('foo.hats');

/**

* 錯 -- 不要這樣作

* @constructor

* @extend {foo.hats.RoundHat}

*/

foo.hats.BowlerHat = function() {

};

若是你須要在外部命名空間中定義新的API,那你應該經過顯式的方法導出公共API函數。自身內部的代碼須要使用這些API時,能夠直接經過內部命名來調用,一是爲了保持一致性,二是能讓編譯器更好的優化代碼。

foo.provide('googleyhats.BowlerHat');

foo.require('foo.hats');

/**

* @constructor

* @extend {foo.hats.RoundHat}

*/

googleyhats.BowlerHat = function() {

...

};

goog.exportSymbol('foo.hats.BowlerHat', googleyhats.BowlerHat);

爲加強可讀性,將長名引用化爲短別名

用局部別名引用完整的包名能夠加強可讀性。局部別名命名應和完整包名的最後一部分相匹配。

/**

* @constructor

*/

some.long.namespace.MyClass = function() {

};

/**

* @param {some.long.namespace.MyClass} a

*/

some.long.namespace.MyClass.staticHelper = function(a) {

...

};

myapp.main = function() {

var MyClass = some.long.namespace.MyClass;

var staticHelper = some.long.namespace.MyClass.staticHelper;

staticHelper(new MyClass());

};

呃……不要別名引用命名空間。

myapp.main = function() {

var namespace = some.long.namespace;

namespace.MyClass.staticHelper(new namespace.MyClass());

};

避免訪問別名引用對象的屬性,除非它是個枚舉。

/** @enum {string} */

some.long.namespace.Fruit = {

APPLE: 'a',

BANANA: 'b'

};

myapp.main = function() {

var Fruit = some.long.namespace.Fruit;

switch (fruit) {

case Fruit.APPLE:

...

case Fruit.BANANA:

...

}

};

myapp.main = function() {

var MyClass = some.long.namespace.MyClass;

MyClass.staticHelper(null);

};

不要在全局做用域中建立別名引用,僅在函數塊中去使用。

文件名

文件名應該所有字母小寫,以免在某些區分大小寫的系統平臺產生文件名混淆。文件名應該以 .js 結束,且不要包含 - 或 _ ( - 比 _ 更好些)。

自定義 toString() 方法

原文

應該老是成功調用,無反作用。

你能夠爲本身的對象定義toString()方法。這是好事呀,可是你要確保你的實現方法知足:(1)老是成功的(2)木有反作用。若是你的方法不知足這兩個條件,運行起來將會很危險。例如,若是 toString() 調用了包含 assert 的方法, assert 可能會試着輸出失敗的對象名,結果又調用了 toString()。

延遲初始化

原文▽能夠。

不必老是在聲明變量的時候就進行初始化,延遲初始化挺好的。

明確做用域

原文

始終須要明確。

任什麼時候候都要明確做用域 - 提升可移植性和清晰度。例如,不要依賴於做用域鏈中的 window 對象。有的時候你可能會想讓你的其餘應用的函數中使用的 window 對象不是以前所指的窗口對象。

代碼格式化

原文▽一兩句話說不明白,展開了詳細討論

咱們鼓勵使用 C++ formatting rules 裏面介紹的代碼格式化規範,還有下面要說的:

大括號

由於分號會被隱式插入代碼中,因此應將大括號和前面的代碼放在一行,以防止誤讀。例如:

if (something) {

// ...

} else {

// ...

}

數組和對象的初始化

合適的話,能夠直接單行進行數組和元素的初始化:

var arr = [1, 2, 3]; // 先後木有空格

var obj = {a: 1, b: 2, c: 3}; // 先後木有空格

多行數組和元素初始化時,最好縮進兩個空格。

// 對象初始化

var inset = {

top: 10,

right: 20,

bottom: 15,

left: 12

};

// 數組初始化

this.rows_ = [

'"Slartibartfast" <fjordmaster@magrathea.com>',

'"Zaphod Beeblebrox" <theprez@universe.gov>',

'"Ford Prefect" <ford@theguide.com>',

'"Arthur Dent" <has.no.tea@gmail.com>',

'"Marvin the Paranoid Android" <marv@googlemail.com>',

'the.mice@magrathea.com'

];

// 直接在方法中調用

goog.dom.createDom(goog.dom.TagName.DIV, {

id: 'foo',

className: 'some-css-class',

style: 'display:none'

}, 'Hello, world!');

在初始化列表中若是碰到了比較長的屬性名或值,不要爲了以爲讓代碼好看些而手工對齊,好比:

CORRECT_Object.prototype = {

a: 0,

b: 1,

lengthyName: 2

};

只有屌絲才這樣作:

WRONG_Object.prototype = {

a : 0,

b : 1,0

lengthyName: 2

};

函數參數

儘量的將全部的函數參數都寫在同一行上,但爲了保持加強可讀性,若是一行超過了80字符的話可適當的換行,甚至能夠每一個參數都獨立一行,記得格式上的優化,好比縮進4個空格和對齊括號。

如下是幾種常見的:

// Four-space, wrap at 80. Works with very long function names, survives

// renaming without reindenting, low on space.

goog.foo.bar.doThingThatIsVeryDifficultToExplain = function(

veryDescriptiveArgumentNumberOne, veryDescriptiveArgumentTwo,

tableModelEventHandlerProxy, artichokeDescriptorAdapterIterator) {

// ...

};

// Four-space, one argument per line. Works with long function names,

// survives renaming, and emphasizes each argument.

goog.foo.bar.doThingThatIsVeryDifficultToExplain = function(

veryDescriptiveArgumentNumberOne,

veryDescriptiveArgumentTwo,

tableModelEventHandlerProxy,

artichokeDescriptorAdapterIterator) {

// ...

};

// Parenthesis-aligned indentation, wrap at 80. Visually groups arguments,

// low on space.

function foo(veryDescriptiveArgumentNumberOne, veryDescriptiveArgumentTwo,

tableModelEventHandlerProxy, artichokeDescriptorAdapterIterator) {

// ...

}

// Parenthesis-aligned, one argument per line. Visually groups and

// emphasizes each individual argument.

function bar(veryDescriptiveArgumentNumberOne,

veryDescriptiveArgumentTwo,

tableModelEventHandlerProxy,

artichokeDescriptorAdapterIterator) {

// ...

}

若是調用的函數自己就已經縮進了,呃你固然能夠針對於當前被調用的函數(或以前的原始函數)再向前縮進4個空格。如下這樣的風格勉強能夠接受:

if (veryLongFunctionNameA(

veryLongArgumentName) ||

veryLongFunctionNameB(

veryLongArgumentName)) {

veryLongFunctionNameC(veryLongFunctionNameD(

veryLongFunctioNameE(

veryLongFunctionNameF)));

}

傳遞匿名函數

若是調用方法傳參內有匿名函數的聲明,函數體應相對於該調用方法(或變量名)縮進2個空格,這樣匿名函數體更易閱讀(而不是將代碼擠到屏幕的另外一半)。

prefix.something.reallyLongFunctionName('whatever', function(a1, a2) {

if (a1.equals(a2)) {

someOtherLongFunctionName(a1);

} else {

andNowForSomethingCompletelyDifferent(a2.parrot);

}

});

var names = prefix.something.myExcellentMapFunction(

verboselyNamedCollectionOfItems,

function(item) {

return item.name;

});

男子漢的縮進是能夠突破天際的!

事實上,除了數組和元素的初始化和傳遞匿名方法之外,都應哦該相對於上一行表達式的左對齊縮進4個空格,而不是2個。

someWonderfulHtml = '' +

getEvenMoreHtml(someReallyInterestingValues, moreValues,

evenMoreParams, 'a duck', true, 72,

slightlyMoreMonkeys(0xfff)) +

'';

thisIsAVeryLongVariableName =

hereIsAnEvenLongerOtherFunctionNameThatWillNotFitOnPrevLine();

thisIsAVeryLongVariableName = 'expressionPartOne' + someMethodThatIsLong() +

thisIsAnEvenLongerOtherFunctionNameThatCannotBeIndentedMore();

someValue = this.foo(

shortArg,

'Some really long string arg - this is a pretty common case, actually.',

shorty2,

this.bar());

if (searchableCollection(allYourStuff).contains(theStuffYouWant) &&

!ambientNotification.isActive() && (client.isAmbientSupported() ||

client.alwaysTryAmbientAnyways())) {

ambientNotification.activate();

}

空行

用空行劃分一組邏輯上相關的代碼,例如:

doSomethingTo(x);

doSomethingElseTo(x);

andThen(x);

nowDoSomethingWith(y);

andNowWith(z);

二元和三元操做符

操做符始終放在前行,這樣就不用顧慮分號的隱式插入的問題,若是一行放不下,能夠參考本節函數參數的寫法。

var x = a ? b : c; // 能放一行的都放在一行裏

// 縮進4個空格木有問題

var y = a ?

longButSimpleOperandB : longButSimpleOperandC;

// 縮進到第一個判斷變量位置木有問題

var z = a ?

moreComplicatedB :

moreComplicatedC;

括號

原文

只在須要的時候使用。

括號的事情可大可小,不必的時候不要用它。

對於一元操做符(如 delete, typeof 和 void)或是某些關鍵字(如return, throw, case, new)後面永遠不要使用括號。

字符串

原文

單引號(')比雙引號(")更好。

使用單引號(')比雙引號(")更好,特別是當建立一個HTML代碼的字符串時候:

var msg = 'This is some HTML';

可見性(私有和受保護的字段)

原文

鼓勵使用JSDoc中的 @private 和 @protected

進行標註。

咱們推薦使用JSDoc的 @private 和 @protected 對類,函數和屬性進行可見性權限的標註。

有個寫作 --jscomp_warning=visibility 的編譯器參數,編輯器會提示違反可見性相關的警告。具體內容請查看 Closure Compiler Warnings.

標註爲 @private 的全局變量和函數,只有其自身文件中的代碼能進行訪問和調用。

構造函數標註了 @private 則表明着只能在自身文件中使用它的公共靜態方法或實例化,也能夠經過 instanceof 操做符進行訪問。

永遠不要爲全局變量,函數和構造函數標記 @protected 。

// 文件 1。

// AA_PrivateClass_ 和 AA_init_ 能夠相互訪問,由於他們在同一個文件裏。

/**

* @private

* @constructor

*/

AA_PrivateClass_ = function() {

};

/** @private */

function AA_init_() {

return new AA_PrivateClass_();

}

AA_init_();

標記 @private 的屬性,自身文件內的代碼能夠訪問,若是這個屬性是某個類的,那此類的全部靜態方法和實例方法也是均可以訪問的。 但來自不一樣文件的子類是沒法訪問或重載該屬性的。

標記 @protected 的屬性,自身文件內的代碼能夠訪問,若是這個屬性是屬於某個類的,那此類包括子類的全部靜態方法和實例方法均可以訪問。

注意,這些語義不一樣於C++和Java,它們容許在同一文件中訪問私有和受保護的屬性,而不僅是限制在同一個類或類繼承中。並且,不向在C++中,私有屬性是不能被子類重載的。

// File 1.

/** @constructor */

AA_PublicClass = function() {

};

/** @private */

AA_PublicClass.staticPrivateProp_ = 1;

/** @private */

AA_PublicClass.prototype.privateProp_ = 2;

/** @protected */

AA_PublicClass.staticProtectedProp = 31;

/** @protected */

AA_PublicClass.prototype.protectedProp = 4;

// File 2.

/**

* @return {number} The number of ducks we've arranged in a row.

*/

AA_PublicClass.prototype.method = function() {

// Legal accesses of these two properties.

return this.privateProp_ + AA_PublicClass.staticPrivateProp_;

};

// File 3.

/**

* @constructor

* @extends {AA_PublicClass}

*/

AA_SubClass = function() {

// Legal access of a protected static property.

AA_PublicClass.staticProtectedProp = this.method();

};

goog.inherits(AA_SubClass, AA_PublicClass);

/**

* @return {number} The number of ducks we've arranged in a row.

*/

AA_SubClass.prototype.method = function() {

// Legal access of a protected instance property.

return this.protectedProp;

};

再注意,在JavaScript中,子類(如 AA_PrivateClass_)和該類的原型類的可見性是相同的,沒有辦法實現兩個子類是公共的,而他們的構造函數倒是私有(由於構造函數很容易別名)。

JavaScript類型

原文

強烈建議使用編譯器。

若是使用JSDoc,那就儘可能按照它的規範去寫,目前支持 JS2 和 JS1.x 兩種規範。

(譯者表示表格裏的單詞太多,要犯懶,想了解詳細信息的能夠查閱JS2

JavaScript類型語言

這個JS2提議爲JavaScript類型定製了一種語言。當咱們在JsDoc中註釋函數參數和返回值類型的時候會用到它。

雖然JS2提議在不斷的進化,但編譯器仍是會繼續支持老的類型語法,只是不建議使用而已。

Operator Name

Syntax

Description

Deprecated Syntaxes

Type Name

{boolean}, {Window}, {goog.ui.Menu}

Simply the name of a type.

Type Application

{Array.<string>}
An array of strings.

{Object.<string, number>}
An object in which the keys are strings and the values are numbers.

Patameterizes a type, by applying a set of type arguments to that type. The idea is analogous to generics in Java.

Type Union

{(number|boolean)}
A number or a boolean.

Indicates that a value might have type A OR type B.

{(number,boolean)},{number|boolean},{(number||boolean)}

Record Type

{{myNum: number, myObject}}
An anonymous type with the given type members.

Indicates that the value has the specified members with the specified types. In this case, myNum with a type number and myObject with any type.

Notice that the braces are part of the type syntax. For example, to denote an Array of objects that have a length property, you might writeArray.<{length}>.

Nullable type

{?number}
A number or NULL.

Indicates that a value is type A or null. By default, all object types are nullable. NOTE: Function types are not nullable.

{number?}

Non-nullable type

{!Object}
An Object, but never the null value.

Indicates that a value is type A and not null. By default, all value types (boolean, number, string, and undefined) are not nullable.

{Object!}

Function Type

{function(string, boolean)}
A function that takes two arguments (a string and a boolean), and has an unknown return value.

Specifies a function.

Function Return Type

{function(): number}
A function that takes no arguments and returns a number.

Specifies a function return type.

Function this Type

{function(this:goog.ui.Menu, string)}
A function that takes one argument (a string), and executes in the context of a goog.ui.Menu.

Specifies the context type of a function type.

Function new Type

{function(new:goog.ui.Menu, string)}
A constructor that takes one argument (a string), and creates a new instance of goog.ui.Menu when called with the 'new' keyword.

Specifies the constructed type of a constructor.

Variable arguments

{function(string, ...[number]): number}
A function that takes one argument (a string), and then a variable number of arguments that must be numbers.

Specifies variable arguments to a function.

Variable arguments (in@param annotations)

@param {...number} var_args
A variable number of arguments to an annotated function.

Specifies that the annotated function accepts a variable number of arguments.

Function optional arguments

{function(?string=, number=)}
A function that takes one optional, nullable string and one optional number as arguments. The = syntax is only for functiontype declarations.

Specifies optional arguments to a function.

Function optional arguments (in @paramannotations)

@param {number=} opt_argument
An optional parameter of type number.

Specifies that the annotated function accepts an optional argument.

The ALL type

{*}

Indicates that the variable can take on any type.

The UNKNOWN type

{?}

Indicates that the variable can take on any type, and the compiler should not type-check any uses of it.

JavaScript的對象類型

類型示例

只示例

描述

number

1

1.0

-5

1e5

Math.PI

數字,整型,浮點型,科學計算型,數字常量

Number

new Number(true)

Number 對象

string

'Hello'

"World"

String(42)

字符串值

String

new String('Hello')

new String(42)

String 對象

boolean

true

false

Boolean(0)

布爾值

Boolean

new Boolean(true)

Boolean 對象

RegExp

new RegExp('hello')

/world/g

正則表達式

Date

new Date

new Date()

日期

null

null

undefined

undefined

void

function f() {

return;

}

返回undefined

Array

['foo', 0.3, null]

[]

混型數組

Array.<number>

[11, 22, 33]

數字型數組

Array.<Array.<string>>

[['one', 'two', 'three'], ['foo', 'bar']]

字符串型數組嵌套數組

Object

{}

{foo: 'abc', bar: 123, baz: null}

對象表達式

Object.<string>

{'foo': 'bar'}

一個對象,鍵和值都是字符串。

Object.<number, string>

var obj = {};

obj[1] = 'bar';

一個對象,鍵是數字,值是字符串。

注意,在JavaScript中,對象的鍵老是會被隱式的轉換成字符串,因此obj['1'] == obj[1]。因此鍵老是以一個字符串的形式在for...in循環中,但若是鍵在索引時,編譯器會驗證類型。

Function

function(x, y) {

return x * y;

}

Function 對象

function(number, number): number

function(x, y) {

return x * y;

}

函數值

SomeClass

/** @constructor */

function SomeClass() {}

new SomeClass();

僞類 - 類實例

SomeInterface

/** @interface */

function SomeInterface() {}

SomeInterface.prototype.draw = function() {};

原型類

project.MyClass

/** @constructor */

project.MyClass = function () {}

new project.MyClass()

構造內部類 - 內部類實例

project.MyEnum

/** @enum {string} */

project.MyEnum = {

BLUE: '#0000dd',

RED: '#dd0000'

};

枚舉

Element

document.createElement('div')

在DOM中建立一個元素節點

Node

document.body.firstChild

返回在DOM中的節點body的第一個子節點

HTMLInputElement

htmlDocument.getElementsByTagName('input')[0]

查找一組特定標籤類型的DOM元素,返回第一個

明確類型

可能出現類型檢查並不能準確判斷表達式的類型的狀況,能夠在註釋裏添加類型標註,並在中括號內寫出表達式的類型,若是有對該類型的註解就更好了。

/** @type {number} */ (x)

(/** @type {number} */ x)

可空 vs.可選的參數和屬性

由於JavaScript是弱類型的語言,理解函數參數和類屬性的可選,可空與未定義之間的區別仍是很重要的。

對象類型(也稱引用類型)默認是可空的,注意:函數類型默認非空。除了字符串,數字,布爾,undefined或null之外,對象能夠是任何類型。例如:

/**

* Some class, initialized with a value.

* @param {Object} value Some value.

* @constructor

*/

function MyClass(value) {

/**

* Some value.

* @type {Object}

* @private

*/

this.myValue_ = value;

}

上段代碼是告訴編譯器 myValue_ 屬性爲一個對象或null。若是 myValue_ 永遠也不能是null,那就應該像下面同樣聲明:

/**

* Some class, initialized with a non-null value.

* @param {!Object} value Some value.

* @constructor

*/

function MyClass(value) {

/**

* Some value.

* @type {!Object}

* @private

*/

this.myValue_ = value;

}

這樣,若是編譯器在代碼中碰到 MyClass 初始化個null值是,就會發出警告。

函數的可選參數可能在運行的時候並無被定義,若是參數引用至類的屬性上,那則須要以下聲明:

/**

* Some class, initialized with an optional value.

* @param {Object=} opt_value Some value (optional).

* @constructor

*/

function MyClass(opt_value) {

/**

* Some value.

* @type {Object|undefined}

* @private

*/

this.myValue_ = opt_value;

}

以上代碼是告訴編譯器說 myValue_ 有多是一個對象,null,還多是 undefined。

注意:可選參數 opt_value 被聲明爲 {Object=},而並非 {Object|undefined}。這是由於可選屬性多是定義的或未定義的,雖說明確寫undefined也不要緊,但讀起來前邊的更爽。

最後,注意可空和可選都是正交屬性,下面的四個聲明都是不一樣的:

/**

* Takes four arguments, two of which are nullable, and two of which are

* optional.

* @param {!Object} nonNull Mandatory (must not be undefined), must not be null.

* @param {Object} mayBeNull Mandatory (must not be undefined), may be null.

* @param {!Object=} opt_nonNull Optional (may be undefined), but if present,

* must not be null!

* @param {Object=} opt_mayBeNull Optional (may be undefined), may be null.

*/

function strangeButTrue(nonNull, mayBeNull, opt_nonNull, opt_mayBeNull) {

// ...

};

類型定義

類型定義也能夠複雜化,一個函數能夠接受元素節點的內容:

/**

* @param {string} tagName

* @param {(string|Element|Text|Array.<Element>|Array.<Text>)} contents

* @return {!Element}

*/

goog.createElement = function(tagName, contents) {

...

};

你能夠定義 @typedef 標記的經常使用類型表達式,例如:

/** @typedef {(string|Element|Text|Array.<Element>|Array.<Text>)} */

goog.ElementContent;

/**

* @param {string} tagName

* @param {goog.ElementContent} contents

* @return {!Element}

*/

goog.createElement = function(tagName, contents) {

...

};

模板屬性

編譯器已經有限的支持模板類型。它只能推斷的類型,這在一個匿名函數字面量從類型的這個論點,是否這個論點是缺失的。The compiler has limited support for template types. It can only infer the type of this inside an anonymous function literal from the type of the this argument and whether the this argument is missing.

/**

* @param {function(this:T, ...)} fn

* @param {T} thisObj

* @param {...*} var_args

* @template T

*/

goog.bind = function(fn, thisObj, var_args) {

...

};

// Possibly generates a missing property warning.

goog.bind(function() { this.someProperty; }, new SomeClass());

// Generates an undefined this warning.

goog.bind(function() { this.someProperty; });

註釋

原文

使用 JSDoc

咱們鼓勵依照 C++ style for comments 的風格。

全部的文件,類,方法和屬性都應該以 JSDoc 風格來進行註釋。

行內註釋使用 // 。

避免出現句式片斷,若是是英文首字母大寫,記得加標點符號。

註釋語法

JSDoc的語法基於JavaDoc 。 許多工具能夠從JSDoc註釋中提取元數據來執行代碼的驗證和優化。固然,前提是這些註釋都是符合語法規則的。

/**

* A JSDoc comment should begin with a slash and 2 asterisks.

* Inline tags should be enclosed in braces like {@code this}.

* @desc Block tags should always start on their own line.

*/

JSDoc 縮進

若是你不得不換行塊標籤,那就應該縮進四個空格以保持註釋內容的結構清晰。

/**

* 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;

};

你不該該縮進 @fileoverview 命令。

儘管縮進至與上排註釋同列並不怎麼好,但也是能夠接受的。

/**

* This is NOT the preferred indentation method.

* @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;

};

JSDocHTML

就像JavaDoc同樣,JSDoc支持好多HTML標籤,如 <code>, <pre>, <tt>, <strong>, <ul>, <ol>, <li>, <a>等等。

昂因此純文本狀態並不會被格式化,好比換行和空格什麼的都會被忽略掉:

/**

* Computes weight based on three factors:

* items sent

* items received

* last timestamp

*/

上面的結果實際上是:

Computes weight based on three factors: items sent items received items received

因此,能夠用這種方式:

/**

* Computes weight based on three factors:

* <ul>

* <li>items sent

* <li>items received

* <li>last timestamp

* </ul>

*/

關於寫註釋更多信息能夠去看一下 JavaDoc 風格指南。

頂部或文件頭的註釋

頂部註釋是爲了讓讀者可以很快的明瞭這個文件裏的代碼是幹嗎的,描述應包括做者,年代,依賴關係或兼容信息等相關,下面的例子:

// Copyright 2009 Google Inc. All Rights Reserved.

/**

* @fileoverview Description of file, its uses and information

* about its dependencies.

* @author user@google.com (Firstname Lastname)

*/

類的註釋

對於類的註釋,確定要寫功能和類型的描述,還有一些參數和原型描述等信息。

/**

* 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);

方法和函數的註釋

應該有參數和返回值的描述,方法描述要以使用者的身份去寫。

/**

* 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) {

// ...

}

一些簡單的get方法沒有參數和其餘影響的,能夠忽略描述。

屬性的描述

/**

* Maximum number of things per pane.

* @type {number}

*/

project.MyClass.prototype.someProperty = 4;

JSDoc標籤參考

(譯者注:看到解釋有一大段,譯者犯懶,有想看的請查閱 JSDoc Toolkit Tag Reference

Tag

Template & Examples

Description

@author

@author username@google.com (first last)

For example:

/**

* @fileoverview Utilities for handling textareas.

* @author kuth@google.com (Uthur Pendragon)

*/

Document the author of a file or the owner of a test, generally only used in the @fileoverviewcomment.

@code

{@code ...}

For example:

/**

* Moves to the next position in the selection.

* Throws {@code goog.iter.StopIteration} when it

* passes the end of the range.

* @return {Node} The node at the next position.

*/

goog.dom.RangeIterator.prototype.next = function() {

// ...

};

Indicates that a term in a JSDoc description is code so it may be correctly formatted in generated documentation.

@const

@const

For example:

/** @const */ var MY_BEER = 'stout';

/**

* My namespace's favorite kind of beer.

* @const

* @type {string}

*/

mynamespace.MY_BEER = 'stout';

/** @const */ MyClass.MY_BEER = 'stout';

Marks a variable as read-only and suitable for inlining. Generates warnings if it is rewritten.

Constants should also be ALL_CAPS, but the annotation should help eliminate reliance on the naming convention. Although @final is listed at jsdoc.org and is supported as equivalent to @const in the compiler, it is discouraged. @const is consistent with JS1.5's const keyword. Note that changes to properties of const objects are not currently prohibited by the compiler (inconsistent with C++ const semantics). The type declaration can be omitted if it can be clearly inferred. If present, it must be on its own line. An additional comment about the variable is optional.

@constructor

@constructor

For example:

/**

* A rectangle.

* @constructor

*/

function GM_Rect() {

...

}

Used in a class's documentation to indicate the constructor.

@define

@define {Type} description

For example:

/** @define {boolean} */

var TR_FLAGS_ENABLE_DEBUG = true;

/** @define {boolean} */

goog.userAgent.ASSUME_IE = false;

Indicates a constant that can be overridden by the compiler at compile-time. In the example, the compiler flag --define='goog.userAgent.ASSUME_IE=true' could be specified in the BUILD file to indicate that the constant goog.userAgent.ASSUME_IE should be replaced with true.

@deprecated

@deprecated Description

For example:

/**

* Determines whether a node is a field.

* @return {boolean} True if the contents of

* the element are editable, but the element

* itself is not.

* @deprecated Use isField().

*/

BN_EditUtil.isTopEditableField = function(node) {

// ...

};

Used to tell that a function, method or property should not be used any more. Always provide instructions on what callers should use instead.

@enum

@enum {Type}

For example:

/**

* Enum for tri-state values.

* @enum {number}

*/

project.TriState = {

TRUE: 1,

FALSE: -1,

MAYBE: 0

};

@export

@export

For example:

/** @export */

foo.MyPublicClass.prototype.myPublicMethod = function() {

// ...

};

Given the code on the left, when the compiler is run with the --generate_exports flag, it will generate the code:

goog.exportSymbol('foo.MyPublicClass.prototype.myPublicMethod',

foo.MyPublicClass.prototype.myPublicMethod);

which will export the symbols to uncompiled code. Code that uses the @export annotation must either

  1. include //javascript/closure/base.js, or
  2. define both goog.exportSymbol and goog.exportProperty with the same method signature in their own codebase.

@extends

@extends Type
@extends {Type}

For example:

/**

* Immutable empty node list.

* @constructor

* @extends goog.ds.BasicNodeList

*/

goog.ds.EmptyNodeList = function() {

...

};

Used with @constructor to indicate that a class inherits from another class. Curly braces around the type are optional.

@externs

@externs

For example:

/**

* @fileoverview This is an externs file.

* @externs

*/

var document;

Declares an externs file.

@fileoverview

@fileoverview Description

For example:

/**

* @fileoverview Utilities for doing things that require this very long

* but not indented comment.

* @author kuth@google.com (Uthur Pendragon)

*/

Makes the comment block provide file level information.

@implements

@implements Type
@implements {Type}

For example:

/**

* A shape.

* @interface

*/

function Shape() {};

Shape.prototype.draw = function() {};

/**

* @constructor

* @implements {Shape}

*/

function Square() {};

Square.prototype.draw = function() {

...

};

Used with @constructor to indicate that a class implements an interface. Curly braces around the type are optional.

@inheritDoc

@inheritDoc

For example:

/** @inheritDoc */

project.SubClass.prototype.toString() {

// ...

};

Deprecated. Use @override instead.

Indicates that a method or property of a subclass intentionally hides a method or property of the superclass, and has exactly the same documentation. Notice that @inheritDoc implies @override.

@interface

@interface

For example:

/**

* A shape.

* @interface

*/

function Shape() {};

Shape.prototype.draw = function() {};

/**

* A polygon.

* @interface

* @extends {Shape}

*/

function Polygon() {};

Polygon.prototype.getSides = function() {};

Used to indicate that the function defines an inteface.

@lends

@lends objectName
@lends {objectName}

For example:

goog.object.extend(

Button.prototype,

/** @lends {Button.prototype} */ {

isButton: function() { return true; }

});

Indicates that the keys of an object literal should be treated as properties of some other object. This annotation should only appear on object literals.

Notice that the name in braces is not a type name like in other annotations. It's an object name. It names the object on which the properties are "lent". For example, @type {Foo} means "an instance of Foo", but @lends {Foo} means "the constructor Foo".

The JSDoc Toolkit docs have more information on this annotation.

@license or@preserve

@license Description

For example:

/**

* @preserve Copyright 2009 SomeThirdParty.

* Here is the full license text and copyright

* notice for this file. Note that the notice can span several

* lines and is only terminated by the closing star and slash:

*/

Anything marked by @license or @preserve will be retained by the compiler and output at the top of the compiled code for that file. This annotation allows important notices (such as legal licenses or copyright text) to survive compilation unchanged. Line breaks are preserved.

@noalias

@noalias

For example:

/** @noalias */

function Range() {}

Used in an externs file to indicate to the compiler that the variable or function should not be aliased as part of the alias externals pass of the compiler.

@nosideeffects

@nosideeffects

For example:

/** @nosideeffects */

function noSideEffectsFn1() {

// ...

};

/** @nosideeffects */

var noSideEffectsFn2 = function() {

// ...

};

/** @nosideeffects */

a.prototype.noSideEffectsFn3 = function() {

// ...

};

This annotation can be used as part of function and constructor declarations to indicate that calls to the declared function have no side-effects. This annotation allows the compiler to remove calls to these functions if the return value is not used.

@override

@override

For example:

/**

* @return {string} Human-readable representation of project.SubClass.

* @override

*/

project.SubClass.prototype.toString() {

// ...

};

Indicates that a method or property of a subclass intentionally hides a method or property of the superclass. If no other documentation is included, the method or property also inherits documentation from its superclass.

@param

@param {Type} varname Description

For example:

/**

* Queries a Baz for items.

* @param {number} groupNum Subgroup id to query.

* @param {string|number|null} term An itemName,

* or itemId, or null to search everything.

*/

goog.Baz.prototype.query = function(groupNum, term) {

// ...

};

Used with method, function and constructor calls to document the arguments of a function.

Type names must be enclosed in curly braces. If the type is omitted, the compiler will not type-check the parameter.

@private

@private

For example:

/**

* Handlers that are listening to this logger.

* @type Array.<Function>

* @private

*/

this.handlers_ = [];

Used in conjunction with a trailing underscore on the method or property name to indicate that the member is private. Trailing underscores may eventually be deprecated as tools are updated to enforce @private.

@protected

@protected

For example:

/**

* Sets the component's root element to the given element. Considered

* protected and final.

* @param {Element} element Root element for the component.

* @protected

*/

goog.ui.Component.prototype.setElementInternal = function(element) {

// ...

};

Used to indicate that the member or property is protected. Should be used in conjunction with names with no trailing underscore.

@return

@return {Type} Description

For example:

/**

* @return {string} The hex ID of the last item.

*/

goog.Baz.prototype.getLastId = function() {

// ...

return id;

};

Used with method and function calls to document the return type. When writing descriptions for boolean parameters, prefer "Whether the component is visible" to "True if the component is visible, false otherwise". If there is no return value, do not use an @return tag.

Type names must be enclosed in curly braces. If the type is omitted, the compiler will not type-check the return value.

@see

@see Link

For example:

/**

* Adds a single item, recklessly.

* @see #addSafely

* @see goog.Collect

* @see goog.RecklessAdder#add

...

Reference a lookup to another class function or method.

@supported

@supported Description

For example:

/**

* @fileoverview Event Manager

* Provides an abstracted interface to the

* browsers' event systems.

* @supported So far tested in IE6 and FF1.5

*/

Used in a fileoverview to indicate what browsers are supported by the file.

@suppress

@suppress {warning1|warning2}

For example:

/**

* @suppress {deprecation}

*/

function f() {

deprecatedVersionOfF();

}

Suppresses warnings from tools. Warning categories are separated by |.

@template

@template

For example:

/**

* @param {function(this:T, ...)} fn

* @param {T} thisObj

* @param {...*} var_args

* @template T

*/

goog.bind = function(fn, thisObj, var_args) {

...

};

This annotation can be used to declare a template typename.

@this

@this Type
@this {Type}

For example:

pinto.chat.RosterWidget.extern('getRosterElement',

/**

* Returns the roster widget element.

* @this pinto.chat.RosterWidget

* @return {Element}

*/

function() {

return this.getWrappedComponent_().getElement();

});

The type of the object in whose context a particular method is called. Required when the thiskeyword is referenced from a function that is not a prototype method.

@type

@type Type
@type {Type}

For example:

/**

* The message hex ID.

* @type {string}

*/

var hexId = hexId;

Identifies the type of a variable, property, or expression. Curly braces are not required around most types, but some projects mandate them for all types, for consistency.

@typedef

@typedef

For example:

/** @typedef {(string|number)} */

goog.NumberLike;

/** @param {goog.NumberLike} x A number or a string. */

goog.readNumber = function(x) {

...

}

This annotation can be used to declare an alias of a more complex type.

推薦使用的有:

@typedef @type @this @template @suppress @supported @see @return @protected @private @param @override @nosideeffects @noalias @lends @interface @inheritDoc @implements @fileoverview @externs @extends @export @enum @deprecated @define @constructor @const @code

你可能在第三方代碼中看到其餘的JSDoc標註。昂它們在Google代碼中並不怎麼鼓勵使用,但誰知道呢可能將來的某一天就忽然的用起來了呢,先看看吧:

  • @augments
  • @argument
  • @borrows
  • @class
  • @constant
  • @constructs
  • @default
  • @event
  • @example
  • @field
  • @function
  • @ignore
  • @inner
  • @link
  • @memberOf
  • @name
  • @namespace
  • @property
  • @public
  • @requires
  • @returns
  • @since
  • @static
  • @version

內部類和枚舉

原文▽內部類和枚舉的定義應和頂級類放在同一文件內。

內部類和枚舉的定義都應和頂級類在同一文件內。goog.provide(google庫的方法,主要功能是註冊類和方法聲明)

只須要聲明頂級類。

編譯壓縮

原文▽推薦使用。

使用被編譯壓縮後的JS代碼能夠更快下載和使用,咳咳,工具的話google推薦 Closure Compiler

提示和技巧

原文

JavaScript 習習更健康。

True False 布爾表達式

如下的表達式都返回false:

  • null
  • undefined
  • '' 空字符串
  • 0 數字0

當心咯,如下的都返回true:

  • '0' 字符串0
  • [] 空數組
  • {} 空對象

你可能會寫下面這段代碼:

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 (經驗證無錯,譯者表示困惑,難道這裏是按照length去判斷的麼)
  • 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">';

&& ||

這倆二元布爾操做符能夠根據前面的代碼判斷後面的代碼是否執行,也就是說只有在必要的時候纔會執行後面的代碼。

"||" 能夠被稱爲默認操做符,由於它能夠代替下面的狀況:

/** @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);

}

但若是這樣的話就有點過了:

node && node.kids && node.kids[index] && foo(node.kids[index]);

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() ,你最好使用賦值的方式。

遍歷節點列表

節點列表是經過節點迭代器和一個過濾器來實現的,這表示它的一個屬性例如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);

}

這種方式對全部集合和數組都適用,固然只要裏面沒有布爾值false。

你也能夠經過 firstChild 和 nextSibling 屬性來遍歷子節點。

var parentNode = document.getElementById('foo');

for (var child = parentNode.firstChild; child; child = child.nextSibling) {

doSomething(child);

}

相關文章
相關標籤/搜索