(設計參考規(guī)范)JAVASCRIPT開發(fā)規(guī)范_第1頁
(設計參考規(guī)范)JAVASCRIPT開發(fā)規(guī)范_第2頁
(設計參考規(guī)范)JAVASCRIPT開發(fā)規(guī)范_第3頁
(設計參考規(guī)范)JAVASCRIPT開發(fā)規(guī)范_第4頁
(設計參考規(guī)范)JAVASCRIPT開發(fā)規(guī)范_第5頁
已閱讀5頁,還剩37頁未讀 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

(設計參考規(guī)范)JAVASCRIPT開發(fā)規(guī)范(設計參考規(guī)范)JAVASCRIPT開發(fā)規(guī)范/(設計參考規(guī)范)JAVASCRIPT開發(fā)規(guī)范JAVASCRIPT開發(fā)規(guī)范一、JavaScript語言規(guī)范JavaScript是一種客戶端腳本語言,Google的許多開源工程中都有用到它.這份指南列出了編寫JavaScript時需要遵守的規(guī)則.Alipay前端JavaScript以些規(guī)范為準,局部有所修改

注:http:///svn/trunk/javascriptguide.xml1.變量

聲明變量必須加上var關鍵字.Decision:當你沒有寫var,變量就會暴露在全局上下文中,這樣很可能會和現(xiàn)有變量沖突.另外,如果沒有加上,很難明確該變量的作用域是什么,變量也很可能像在局部作用域中,很輕易地泄漏到Document或者Window中,所以務必用var去聲明變量.2.常量常量的形式如:NAMES_LIKE_THIS,即使用大寫字符,并用下劃線分隔.你也可用@const標記來指明它是一個常量.但請永遠不要使用const關鍵詞.Decision:

(1)對于基本類型的常量,只需轉換命名.

/**

*Thenumberofsecondsinaminute.

*@type{number}

*/

goog.example.SECONDS_IN_A_MINUTE=60;

(2)對于非基本類型,使用@const標記.

/**

*Thenumberofsecondsineachofthegivenunits.

*@type{Object.<number>}

*@const

*/

goog.example.SECONDS_TABLE={

minute:60,

hour:60*60,

day:60*60*24

}

這標記告訴編譯器它是常量.

至于關鍵詞const,因為IE不能識別,所以不要使用.3.分號總是使用分號.如果僅依靠語句間的隱式分隔,有時會很麻煩.你自己更能清楚哪里是語句的起止.而且有些情況下,漏掉分號會很危險:

//1.

MyCtotype.myMethod=function(){

return42;

}//Nosemicolonhere.

(function(){

//Someinitializationcodewrappedinafunctiontocreateascopeforlocals.

})();

varx={

'i':1,

'j':2

}//Nosemicolonhere.

//2.TryingtodoonethingonInternetExplorerandanotheronFirefox.

//Iknowyou'dneverwritecodelikethis,butthrowmeabone.

[normalVersion,ffVersion][isIE]();

varTHINGS_TO_EAT=[apples,oysters,sprayOnCheese]//Nosemicolonhere.

//3.conditionalexecutionalabash

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

這段代碼會發(fā)生些什么詭異事呢?報JavaScript錯誤-例子1上的語句會解釋成,一個函數帶一匿名函數作為參數而被調用,返回42后,又一次被"調用",這就導致了錯誤.例子2中,你很可能會在運行時遇到'nosuchpropertyinundefined'錯誤,原因是代碼試圖這樣x[ffVersion][isIE]()執(zhí)行.當resultOfOperation()返回非NaN時,就會調用die,其結果也會賦給THINGS_TO_EAT.為什么?JavaScript的語句以分號作為結束符,除非可以非常準確推斷某結束位置才會省略分號.上面的幾個例子產出錯誤,均是在語句中聲明了函數/對象/數組直接量,但閉括號('}'或']')并不足以表示該語句的結束.在JavaScript中,只有當語句后的下一個符號是后綴或括號運算符時,才會認為該語句的結束.遺漏分號有時會出現(xiàn)很奇怪的結果,所以確保語句以分號結束.4.嵌套函數可以使用嵌套函數很有用,比如,減少重復代碼,隱藏幫助函數,等.沒什么其他需要注意的地方,隨意使用.5.塊內函數聲明不要在塊內聲明一個函數,不要寫成:

if(x){

functionfoo(){}

}雖然很多JS引擎都支持塊內聲明函數,但它不屬于ECMAScript規(guī)范(見ECMA-262,第13和14條).各個瀏覽器糟糕的實現(xiàn)相互不兼容,有些也與未來ECMAScript草案相違背.ECMAScript只允許在腳本的根語句或函數中聲明函數.如果確實需要在塊中定義函數,建議使用函數表達式來初始化變量:

if(x){

varfoo=function(){}

}6.異常可以你在寫一個比較復雜的應用時,不可能完全避免不會發(fā)生任何異常.大膽去用吧.7.自定義異??梢杂袝r發(fā)生異常了,但返回的錯誤信息比較奇怪,也不易讀.雖然可以將含錯誤信息的引用對象或者可能產生錯誤的完整對象傳遞過來,但這樣做都不是很好,最好還是自定義異常類,其實這些基本上都是最原始的異常處理技巧.所以在適當的時候使用自定義異常.8.標準特性總是優(yōu)于非標準特性.最大化可移植性和兼容性,盡量使用標準方法而不是用非標準方法,(比如,優(yōu)先用string.charAt(3)而不用string[3],通過DOM原生函數訪問元素,而不是使用應用封裝好的快速接口.9.封裝基本類型不要沒有任何理由去封裝基本類型,另外還存在一些風險:varx=newBoolean(false);

if(x){

alert('hi');//Shows'hi'.

}除非明確用于類型轉換,其他情況請千萬不要這樣做!varx=Boolean(0);

if(x){

alert('hi');//Thiswillneverbealerted.

}

typeofBoolean(0)=='boolean';

typeofnewBoolean(0)=='object';有時用作number,string或boolean時,類型的轉換會非常實用.10.多級原型結構不是首選多級原型結構是指JavaScript中的繼承關系.當你自定義一個D類,且把B類作為其原型,那么這就獲得了一個多級原型結構.這些原型結構會變得越來越復雜!使用Arale中的inherits或其他類似的用于繼承的函數,會是更好的選擇.functionMyClass(){

doSomeThing()

}

arale.inherits(MyClass,Parent);

MyCtotype.method=function(){

...

};11.方法定義Ftotype.bar=function(){...};有很多方法可以給構造器添加方法或成員,我們更傾向于使用如下的形式:Ftotype.bar=function(){

/*...*/

};12.閉包可以,但小心使用.閉包也許是JS中最有用的特性了.有一份比較好的介紹閉包原理的文檔.有一點需要牢記,閉包保留了一個指向它封閉作用域的指針,所以,在給DOM元素附加閉包時,很可能會產生循環(huán)引用,進一步導致內存泄漏.比如下面的代碼:functionfoo(element,a,b){

element.onclick=function(){/*usesaandb*/};

}這里,即使沒有使用element,閉包也保留了element,a和b的引用,.由于element也保留了對閉包的引用,這就產生了循環(huán)引用,這就不能被GC回收.這種情況下,可將代碼重構為:

functionfoo(element,a,b){

element.onclick=bar(a,b);

}

functionbar(a,b){

returnfunction(){/*usesaandb*/}

}13.eval()只用于解析序列化串(如:解析RPC響應)eval()會讓程序執(zhí)行的比較混亂,當eval()里面包含用戶輸入的話就更加危險.可以用其他更佳的,更清晰,更安全的方式寫你的代碼,所以一般情況下請不要使用eval().當碰到一些需要解析序列化串的情況下(如,計算RPC響應),使用eval很容易實現(xiàn).解析序列化串是指將字節(jié)流轉換成內存中的數據結構.比如,你可能會將一個對象輸出成文件形式:users=[

{

name:'Eric',

id:37824,

email:'jellyvore@'

},

{

name:'xtof',

id:31337,

email:'b4d455h4x0r@'

},

...

];很簡單地調用eval后,把表示成文件的數據讀取回內存中.類似的,eval()對RPC響應值進行解碼.例如,你在使用XMLHttpRequest發(fā)出一個RPC請求后,通過eval()將服務端的響應文本轉成JavaScript對象:

varuserOnline=false;

varuser='nusrat';

varxmlhttp=newXMLHttpRequest();

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

xmlhttp.send('');

//Serverreturns:

//userOnline=true;

if(xmlhttp.status==200){

eval(xmlhttp.responseText);

}

//userOnlineisnowtrue.14.with(){}不要使用使用with讓你的代碼在語義上變得不清晰.因為with的對象,可能會與局部變量產生沖突,從而改變你程序原本的用義.下面的代碼是干嘛的?with(foo){

varx=3;

returnx;

}答案:任何事.局部變量x可能被foo的屬性覆蓋,當它定義一個setter時,在賦值3后會執(zhí)行很多其他代碼.所以不要使用with語句.15.this僅在對象構造器,方法,閉包中使用.this的語義很特別.有時它引用一個全局對象(大多數情況下),調用者的作用域(使用eval時),DOM樹中的節(jié)點(添加事件處理函數時),新創(chuàng)建的對象(使用一個構造器),或者其他對象(如果函數被call()或apply()).使用時很容易出錯,所以只有在下面兩個情況時才能使用:

在構造器中對象的方法(包括創(chuàng)建的閉包)中16.for-in循環(huán)只用于object/map/hash的遍歷對Array用for-in循環(huán)有時會出錯.因為它并不是從0到length-1進行遍歷,而是所有出現(xiàn)在對象及其原型鏈的鍵值.下面就是一些失敗的使用案例:functionprintArray(arr){

for(varkeyinarr){

print(arr[key]);

}

}

printArray([0,1,2,3]);//Thisworks.

vara=newArray(10);

printArray(a);//Thisiswrong.

a=document.getElementsByTagName('*');

printArray(a);//Thisiswrong.

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

a.buhu='wine';

printArray(a);//Thisiswrongagain.

a=newArray;

a[3]=3;

printArray(a);//Thisiswrongagain.而遍歷數組通常用最普通的for循環(huán).

functionprintArray(arr){

varl=arr.length;

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

print(arr[i]);

}

}17.關聯(lián)數組永遠不要使用Array作為map/hash/associative數組.數組中不允許使用非整型作為索引值,所以也就不允許用關聯(lián)數組.而取代它使用Object來表示map/hash對象.Array僅僅是擴展自Object(類似于其他JS中的對象,就像Date,RegExp和String)一樣來使用.18.多行字符串不要使用不要這樣寫長字符串:varmyString='AratherlongstringofEnglishtext,anerrormessage\

actuallythatjustkeepsgoingandgoing--anerror\

messagetomaketheEnergizerbunnyblush(rightthrough\

thoseSchwarzeneggershades)!WherewasI?Ohyes,\

you\'vegotanerrorandalltheextraneouswhitespaceis\

justgravy.Haveaniceday.';

在編譯時,不能忽略行起始位置的空白字符;"\"后的空白字符會產生奇怪的錯誤;雖然大多數腳本引擎支持這種寫法,但它不是ECMAScript的標準規(guī)范.19.Array和Object字面量使用使用Array和Object語法,而不使用Array和Object構造器.使用Array構造器很容易因為傳參不恰當導致錯誤.

//Lengthis3.

vara1=newArray(x1,x2,x3);

//Lengthis2.

vara2=newArray(x1,x2);

//Ifx1isanumberanditisanaturalnumberthelengthwillbex1.

//Ifx1isanumberbutnotanaturalnumberthiswillthrowanexception.

//Otherwisethearraywillhaveoneelementwithx1asitsvalue.

vara3=newArray(x1);

//Lengthis0.

vara4=newArray();如果傳入一個參數而不是2個參數,數組的長度很有可能就不是你期望的數值了.為了避免這些歧義,我們應該使用更易讀的直接量來聲明.

vara=[x1,x2,x3];

vara2=[x1,x2];

vara3=[x1];

vara4=[];雖然Object構造器沒有上述類似的問題,但鑒于可讀性和一致性考慮,最好還是在字面上更清晰地指明.

varo=newObject();

varo2=newObject();

o2.a=0;

o2.b=1;

o2.c=2;

o2['strangekey']=3;

應該寫成:

varo={};

varo2={

a:0,

b:1,

c:2,

'strangekey':3

};20.修改內置對象的原型不要千萬不要修改內置對象,如Ototype和Atotype的原型.而修改內置對象,如Ftotype的原型,雖然少危險些,但仍會導致調試時的詭異現(xiàn)象.所以也要避免修改其原型.21.IE下的條件注釋不要使用不要這樣子寫:

varf=function(){

/@cc_onif(@_jscript){return2*@/3;/@}@/

};

條件注釋妨礙自動化工具的執(zhí)行,因為在運行時,它們會改變JavaScript語法樹.二、JavaScript編碼風格1.命名

通常,使用functionNamesLikeThis,variableNamesLikeThis,ClassNamesLikeThis,EnumNamesLikeThis,methodNamesLikeThis,和SYMBOLIC_CONSTANTS_LIKE_THIS.A.屬性和方法文件或類中的私有屬性,變量和方法名應該以下劃線"_"開頭.保護屬性,變量和方法名不需要下劃線開頭,和公共變量名一樣.

更多有關私有和保護的信息見,visibility.B.方法和函數參數

可選參數以opt_開頭.函數的參數個數不固定時,應該添加最后一個參數var_args為參數的個數.你也可以不設置var_args而取代使用arguments.可選和可變參數應該在@param標記中說明清楚.雖然這兩個規(guī)定對編譯器沒有任何影響,但還是請盡量遵守C.Getters和Setters

Getters和setters并不是必要的.但只要使用它們了,就請將getters命名成getFoo()形式,將setters命名成setFoo(value)形式.(對于布爾類型的getters,使用isFoo()也可.)D.命名空間JavaScript不支持包和命名空間.不容易發(fā)現(xiàn)和調試全局命名的沖突,多個系統(tǒng)集成時還可能因為命名沖突導致很嚴重的問題.為了提高JavaScript代碼復用率,我們遵循下面的約定以避免沖突.為全局代碼使用命名空間在全局作用域上,使用一個唯一的,與工程/庫相關的名字作為前綴標識.比如,你的工程是"ProjectSloth",那么命名空間前綴可取為sloth.*.

varsloth={};

sloth.sleep=function(){

...

};許多JavaScript庫,包括theClosureLibraryandDojotoolkit為你提供了聲明你自己的命名空間的函數.比如:

vide('sloth');

sloth.sleep=function(){

...

};明確命名空間所有權

當選擇了一個子命名空間,請確保父命名空間的負責人知道你在用哪個子命名空間,比如說,你為工程'sloths'創(chuàng)建一個'hats'子命名空間,那確保Sloth團隊人員知道你在使用sloth.hats.外部代碼和內部代碼使用不同的命名空間"外部代碼"是指來自于你代碼體系的外部,可以獨立編譯.內外部命名應該嚴格保持獨立.如果你使用了外部庫,他的所有對象都在foo.hats.*下,那么你自己的代碼不能在foo.hats.*下命名,因為很有可能其他團隊也在其中命名.

foo.require('foo.hats');

/**

*WRONG--DoNOTdothis.

*@constructor

*@extend{foo.hats.RoundHat}

*/

foo.hats.BowlerHat=function(){

};

如果你需要在外部命名空間中定義新的API,那么你應該直接導出一份外部庫,然后在這份代碼中修改.在你的內部代碼中,應該通過他們的內部名字來調用內部API,這樣保持一致性可讓編譯器更好的優(yōu)化你的代碼.

vide('googleyhats.BowlerHat');

foo.require('foo.hats');

/**

*@constructor

*@extend{foo.hats.RoundHat}

*/

googleyhats.BowlerHat=function(){

...

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

重命名那些名字很長的變量,提高可讀性主要是為了提高可讀性.局部空間中的變量別名只需要取原名字的最后部分.

/**

*@constructor

*/

space.MyClass=function(){

};

/**

*@param{space.MyClass}a

*/

space.MyClass.staticHelper=function(a){

...

};

myapp.main=function(){

varMyClass=space.MyClass;

varstaticHelper=space.MyClass.staticHelper;

staticHelper(newMyClass());

};

不要對命名空間創(chuàng)建別名.

myapp.main=function(){

varnamespace=space;

namespace.MyClass.staticHelper(newnamespace.MyClass());

};

除非是枚舉類型,不然不要訪問別名變量的屬性.

/**@enum{string}*/

space.Fruit={

APPLE:'a',

BANANA:'b'

};

myapp.main=function(){

varFruit=space.Fruit;

switch(fruit){

caseFruit.APPLE:

...

caseFruit.BANANA:

...

}

};myapp.main=function(){

varMyClass=space.MyClass;

MyClass.staticHelper(null);

};

不要在全局范圍內創(chuàng)建別名,而僅在函數塊作用域中使用.E.文件名

文件名應該使用小寫字符,以避免在有些系統(tǒng)平臺上不識別大小寫的命名方式.文件名以.js結尾,不要包含除-和_外的標點符號(使用-優(yōu)于_).F.JS鉤子

JS鉤子一律使用"J-”前綴,如:#J-ui-repeater2.自定義toString()方法應該總是成功調用且不要拋異常.可自定義toString()方法,但確保你的實現(xiàn)方法滿足:總是成功沒有其他負面影響.如果不滿足這兩個條件,那么可能會導致嚴重的問題,比如,如果toString()調用了包含assert的函數,assert輸出導致失敗的對象,這在toString()也會被調用.3.延遲初始化可以沒必要在每次聲明變量時就將其初始化.4.明確作用域任何時候都需要任何時候都要明確作用域-提高可移植性和清晰度.例如,不要依賴于作用域鏈中的window對象.可能在其他應用中,你函數中的window不是指之前的那個窗口對象.5.代碼格式化

主要依照C++格式規(guī)范(中文版),針對JavaScript,還有下面一些附加說明.A.大括號

分號會被隱式插入到代碼中,所以你務必在同一行上插入大括號.例如:

if(something){

//...

}else{

//...

}B.數組和對象的初始化如果初始值不是很長,就保持寫在單行上:

vararr=[1,2,3];//Nospaceafter[orbefore].

varobj={a:1,b:2,c:3};//Nospaceafter{orbefore}.初始值占用多行時,縮進2個空格.

//Objectinitializer.

varinset={

top:10,

right:20,

bottom:15,

left:12};

//Arrayinitializer.

this.rows_=[

'"Slartibartfast"<fjordmaster@>',

'"ZaphodBeeblebrox"<theprez@>',

'"FordPrefect"<ford@>',

'"ArthurDent"<has.no.tea@>',

'"MarvintheParanoidAndroid"<marv@>',

'the.mice@'];

//Usedinamethodcall.

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

id:'foo',

className:'some-css-class',

style:'display:none'

},'Hello,world!');比較長的標識符或者數值,不要為了讓代碼好看些而手工對齊.如:

CORRECT_Ototype={

a:0,

b:1,

lengthyName:2

};不要這樣做:

WRONG_Ototype={

a:0,

b:1,

lengthyName:2

};C.函數參數盡量讓函數參數在同一行上.如果一行超過80字符,每個參數獨占一行,并以4個空格縮進,或者與括號對齊,以提高可讀性.盡可能不要讓每行超過80個字符.比如下面這樣:

//Four-space,wrapat80.Workswithverylongfunctionnames,survives

//renamingwithoutreindenting,lowonspace.

goog.foo.bar.doThingThatIsVeryDifficultToExplain=function(

veryDescriptiveArgumentNumberOne,veryDescriptiveArgumentTwo,

tableModelEventHandlerProxy,artichokeDescriptorAdapterIterator){

//...

};

//Four-space,oneargumentperline.Workswithlongfunctionnames,

//survivesrenaming,andemphasizeseachargument.

goog.foo.bar.doThingThatIsVeryDifficultToExplain=function(

veryDescriptiveArgumentNumberOne,

veryDescriptiveArgumentTwo,

tableModelEventHandlerProxy,

artichokeDescriptorAdapterIterator){

//...

};

//Parenthesis-alignedindentation,wrapat80.Visuallygroupsarguments,

//lowonspace.

functionfoo(veryDescriptiveArgumentNumberOne,veryDescriptiveArgumentTwo,

tableModelEventHandlerProxy,artichokeDescriptorAdapterIterator){

//...

}

//Parenthesis-aligned,oneargumentperline.Visuallygroupsand

//emphasizeseachindividualargument.

functionbar(veryDescriptiveArgumentNumberOne,

veryDescriptiveArgumentTwo,

tableModelEventHandlerProxy,

artichokeDescriptorAdapterIterator){

//...

}D.傳遞匿名函數

如果參數中有匿名函數,函數體從調用該函數的左邊開始縮進2個空格,而不是從function這個關鍵字開始.這讓匿名函數更加易讀(不要增加很多沒必要的縮進讓函數體顯示在屏幕的右側).varnames=items.map(function(item){

return;

});

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

if(a1.equals(a2)){

someOtherLongFunctionName(a1);

}else{

andNowForSomethingCompletelyDifferent(a2.parrot);

}

});E.更多的縮進事實上,除了初始化數組和對象,和傳遞匿名函數外,所有被拆開的多行文本要么選擇與之前的表達式左對齊,要么以4個(而不是2個)空格作為一縮進層次.

someWonderfulHtml=''+

getEvenMoreHtml(someReallyInterestingValues,moreValues,

evenMoreParams,'aduck',true,72,

slightlyMoreMonkeys(0xfff))+

'';

thisIsAVeryLongVariableName=

hereIsAnEvenLongerOtherFunctionNameThatWillNotFitOnPrevLine();

thisIsAVeryLongVariableName='expressionPartOne'+someMethodThatIsLong()+

thisIsAnEvenLongerOtherFunctionNameThatCannotBeIndentedMore();

someValue=this.foo(

shortArg,

'Somereallylongstringarg-thisisaprettycommoncase,actually.',

shorty2,

this.bar());

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

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

client.alwaysTryAmbientAnyways()){

ambientNotification.activate();

}F.空行使用空行來劃分一組邏輯上相關聯(lián)的代碼片段.

doSomethingTo(x);

doSomethingElseTo(x);

andThen(x);

nowDoSomethingWith(y);

andNowWith(z);G.二元和三元操作符操作符始終跟隨著前行,這樣就不用顧慮分號的隱式插入問題.如果一行實在放不下,還是按照上述的縮進風格來換行.varx=a?b:c;//Allononelineifitwillfit.

//Indentation+4isOK.

vary=a?

longButSimpleOperandB:longButSimpleOperandC;

//IndentingtothelinepositionofthefirstoperandisalsoOK.

varz=a?

moreComplicatedB:

moreComplicatedC;6.括號只在需要的時候使用不要濫用括號,只在必要的時候使用它.對于一元操作符(如delete,typeof和void),或是在某些關鍵詞(如return,throw,case,new)之后,不要使用括號.7.字符串使用'優(yōu)于"單引號(')優(yōu)于雙引號(").當你創(chuàng)建一個包含HTML代碼的字符串時就知道它的好處了.varmsg='ThisissomeHTML';8.可見性(私有域和保護域)推薦使用JSDoc中的兩個標記:@private和@protectedJSDoc的兩個標記@private和@protected用來指明類,函數,屬性的可見性域.標記為@private的全局變量和函數,表示它們只能在當前文件中訪問.標記為@private的構造器,表示該類只能在當前文件或是其靜態(tài)/普通成員中實例化;私有構造器的公共靜態(tài)屬性在當前文件的任何地方都可訪問,通過instanceof操作符也可.永遠不要為全局變量,函數,構造器加@protected標記.//File1.

//AA_PrivateClass_andAA_init_areaccessiblebecausetheyareglobal

//andinthesamefile.

/**

*@private

*@constructor

*/

AA_PrivateClass_=function(){

};

/**@private*/

functionAA_init_(){

returnnewAA_PrivateClass_();

}

AA_init_();

標記為@private的屬性,在當前文件中可訪問它;如果是類屬性私有,"擁有"該屬性的類的所有靜態(tài)/普通成員也可訪問,但它們不能被不同文件中的子類訪問或覆蓋.標記為@protected的屬性,在當前文件中可訪問它,如果是類屬性保護,那么"擁有"該屬性的類及其子類中的所有靜態(tài)/普通成員也可訪問.注意:這與C+,Java中的私有和保護不同,它們是在當前文件中,檢查是否具有訪問私有/保護屬性的權限,有權限即可訪問,而不是只能在同一個類或類層次上.而C+中的私有屬性不能被子類覆蓋.(C++/Java中的私有/保護是指作用域上的可訪問性,在可訪問性上的限制.JS中是在限制在作用域上.PS:可見性是與作用域對應)

//File1.

/**@constructor*/

AA_PublicClass=function(){

};

/**@private*/

AA_PublicClass.staticPrivateProp_=1;

/**@private*/

AA_PublicCtotype.privateProp_=2;

/**@protected*/

AA_PublicClass.staticProtectedProp=31;

/**@protected*/

AA_PublicCtectedProp=4;

//File2.

/**

*@return{number}Thenumberofduckswe'vearrangedinarow.

*/

AA_PublicCtotype.method=function(){

//Legalaccessesofthesetwoproperties.

returnthis.privateProp_+AA_PublicClass.staticPrivateProp_;

};

//File3.

/**

*@constructor

*@extends{AA_PublicClass}

*/

AA_SubClass=function(){

//Legalaccessofaprotectedstaticproperty.

AA_PublicClass.staticProtectedProp=this.method();

};

goog.inherits(AA_SubClass,AA_PublicClass);

/**

*@return{number}Thenumberofduckswe'vearrangedinarow.

*/

AA_SubCtotype.method=function(){

//Legalaccessofaprotectedinstanceproperty.

returntectedProp;

};9.JavaScript類型強烈建議你去使用編譯器.如果使用JSDoc,那么盡量具體地,準確地根據它的規(guī)則來書寫類型說明.目前支持兩種JS2和JS1.x類型規(guī)范.JavaScript類型語言JS2提議中包含了一種描述JavaScript類型的規(guī)范語法,這里我們在JSDoc中采用其來描述函數參數和返回值的類型.JSDoc的類型語言,按照JS2規(guī)范,也進行了適當改變,但編譯器仍然支持舊語法.

名稱語法描述棄用語法普通類型{boolean},{Window},{goog.ui.Menu}普通類型的描述方法.

復雜類型{Array.<string>}

字符串數組.{Object.<string,number>}

鍵為字符串,值為整數的對象類型.參數化類型,即指定了該類型中包含的一系列"類型參數".類似于Java中的泛型.

聯(lián)合類型{(number|boolean)}

一個整數或者布爾值.表示其值可能是A類型,也可能是B類型{(number,boolean)},{number|boolean},{(number||boolean)}記錄類型myNum:number,myObject

由現(xiàn)有類型組成的類型.表示包含指定成員及類型的值.這個例子中,myNum為number類型,myObject為任意類型.

注意大括號為類型語法的一部分.比如,Array.<{length}>,表示一具有l(wèi)ength屬性的Array對象.

可為空類型{?number}

一個整型數或者為NULL表示一個值可能是A類型或者null.默認,每個對象都是可為空的.注意:函數類型不可為空.{number?}非空類型{!Object}

一個對象,但絕不會是null值.說明一個值是類型A且肯定不是null.默認情況下,所有值類型(boolean,number,string,和undefined)不可為空.{Object!}函數類型{function(string,boolean)}

具有兩個參數(string和boolean)的函數類型,返回值未知.說明一個函數.

函數返回類型{function():number}

函數返回一個整數.說明函數的返回類型.

函數的this類型{function(this:goog.ui.Menu,string)}

函數只帶一個參數(string),并且在上下文goog.ui.Menu中執(zhí)行.說明函數類型的上下文類型.

可變參數{function(string,...[number]):number}

帶一個參數(字符類型)的函數類型,并且函數的參數個數可變,但參數類型必須為number.說明函數的可變長參數.

可變長的參數(使用@param標記)@param{...number}var_args

函數參數個數可變.使用標記,說明函數具有不定長參數.

函數的缺省參數{function(?string=,number=)}

函數帶一個可空且可選的字符串型參數,一個可選整型參數.=語法只針對function類型有效.說明函數的可選參數.

函數可選參數(使用@param標記)@param{number=}opt_argument

number類型的可選參數.使用標記,說明函數具有可選參數.

所有類型{*}表示變量可以是任何類型.

JavaScript中的類型

類型示例值示例描述number1

1.0

-5

1e5

Math.PI

NumbernewNumber(true)Number對象string'Hello'

"World"

String(42)字符串值StringnewString('Hello')

newString(42)字符串對象booleantrue

false

Boolean(0)布爾值BooleannewBoolean(true)布爾對象RegExpnewRegExp('hello')

/world/g

DatenewDate

newDate()

nullnull

undefinedundefined

voidfunctionf(){

return;

}沒有返回值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>varobj={};

obj[1]='bar';鍵為整數,值為字符串的對象.注意,JavaScript中,鍵總是被轉換成字符串,所以obj['1']==obj[1].也所以,鍵在for...in循環(huán)中是字符串類型.但在編譯器中會明確根據鍵的類型來查找對象.Functionfunction(x,y){

returnx*y;

}函數對象function(number,number):numberfunction(x,y){

returnx*y;

}函數值SomeClass/**@constructor*/

functionSomeClass(){}

newSomeClass();

SomeInterface/**@interface*/

functionSomeInterface(){}

SomeItotype.draw=function(){};

project.MyClass/**@constructor*/

project.MyClass=function(){}

newproject.MyClass()

project.MyEnum/**@enum{string}*/

project.MyEnum={

BLUE:'#0000dd',

RED:'#dd0000'

};枚舉Elementdocument.createElement('div')DOM中的元素Nodedocument.body.firstChildDOM中的節(jié)點.HTMLInputElementhtmlDocument.getElementsByTagName('input')[0]DOM中,特定類型的元可空vs.可選參數和屬性

JavaScript是一種弱類型語言,明白可選,非空和未定義參數或屬性之間的細微差別還是很重要的.

對象類型(引用類型)默認非空.注意:函數類型默認不能為空.除了字符串,整型,布爾,undefined和null外,對象可以是任何類型.

/**

*Someclass,initializedwithavalue.

*@param{Object}valueSomevalue.

*@constructor

*/

functionMyClass(value){

/**

*Somevalue.

*@type{Object}

*@private

*/

this.myValue_=value;

}

告訴編譯器myValue_屬性為一對象或null.如果myValue_永遠都不會為null,就應該如下聲明:

/**

*Someclass,initializedwithanon-nullvalue.

*@param{!Object}valueSomevalue.

*@constructor

*/

functionMyClass(value){

/**

*Somevalue.

*@type{!Object}

*@private

*/

this.myValue_=value;

}

這樣,當編譯器在代碼中碰到MyClass為null時,就會給出警告.函數的可選參數可能在運行時沒有定義,所以如果他們又被賦給類屬性,需要聲明成:

/**

*Someclass,initializedwithanoptionalvalue.

*@param{Object=}opt_valueSomevalue(optional).

*@constructor

*/

functionMyClass(opt_value){

/**

*Somevalue.

*@type{Object|undefined}

*@private

*/

this.myValue_=opt_value;

}

這告訴編譯器myValue_可能是一個對象,或null,或undefined.

注意:可選參數opt_value被聲明成{Object=},而不是{Object|undefined}.這是因為可選參數可能是undefined.雖然直接寫undefined也并無害處,但鑒于可閱讀性還是寫成上述的樣子.

最后,屬性的非空和可選并不矛盾,屬性既可是非空,也可是可選的.下面的四種聲明各不相同:

/**

*Takesfourarguments,twoofwhicharenullable,andtwoofwhichare

*optional.

*@param{!Object}nonNullMandatory(mustnotbeundefined),mustnotbenull.

*@param{Object}mayBeNullMandatory(mustnotbeundefined),maybenull.

*@param{!Object=}opt_nonNullOptional(maybeundefined),butifpresent,

*mustnotbenull!

*@param{Object=}opt_mayBeNullOptional(maybeundefined),maybenull.

*/

functionstrangeButTrue(nonNull,mayBeNull,opt_nonNull,opt_mayBeNull){

//...

};10.注釋A.使用JSDoc

我們使用JSDoc中的注釋風格.行內注釋使用//變量的形式.另外,我們也遵循C++代碼注釋風格.這也就是說你需要:版權和著作權的信息,文件注釋中應該寫明該文件的基本信息(如,這段代碼的功能摘要,如何使用,與哪些東西相關),來告訴那些不熟悉代碼的讀者.類,函數,變量和必要的注釋,期望在哪些瀏覽器中執(zhí)行,正確的大小寫,標點和拼寫.

為了避免出現(xiàn)句子片段,請以合適的大/小寫單詞開頭,并以合適的標點符號結束這個句子.現(xiàn)在假設維護這段代碼的是一位初學者.這可能正好是這樣的!目前很多編譯器可從JSDoc中提取類型信息,來對代碼進行驗證,刪除和壓縮.因此,你很有必要去熟悉正確完整的JSDoc.B.頂層/文件注釋

頂層注釋用于告訴不熟悉這段代碼的讀者這個文件中包含哪些東西.應該提供文件的大體內容,它的作者,依賴關系和兼容性信息.如下:

//Copyright2009GoogleInc.AllRightsReserved.

/**

*@Descriptionoffile,itsusesandinformation

*aboutitsdependencies.

*@authoruser@(FirstnameLastname)

*/C.類注釋每個類的定義都要附帶一份注釋,描述類的功能和用法.也需要說明構造器參數.如果該類繼承自其它類,應該使用@extends標記.如果該類是對接口的實現(xiàn),應該使用@implements標記.

/**

*Classmakingsomethingfunandeasy.

*@param{string}arg1Anargumentthatmakesthismoreinteresting.

*@param{Array.<number>}arg2Listofnumberstobeprocessed.

*@constructor

*@extends{goog.Disposable}

*/

project.MyClass=function(arg1,arg2){

//...

};

goog.inherits(project.MyClass,goog.Disposable);方法與函數的注釋.提供參數的說明.使用完整的句子,并用第三人稱來書寫方法說明.

/**

*Convertstexttosomecompletelydifferenttext.

*@param{string}arg1Anargumentthatmakesthismoreinteresting.

*@return{string}Somereturnvalue.

*/

project.MyCtotype.someMethod=function(arg1){

//...

};

/**

*OperatesonaninstanceofMyClassandreturnssomething.

*@param{project.MyClass}objInstanceofMyClasswhichleadstoalong

*commentthatneedstobewrappedtotwolines.

*@return{boolean}Whethersomethingoccured.

*/

functionPR_someMethod(obj){

//...

}對于一些簡單的,不帶參數的getters,說明可以忽略.

/**

*@return{Element}Theelementforthecomponent.

*/

goog.ui.Ctotype.getElement=function(){

returnthis.element_;

};D.屬性注釋

需要對屬性進行注釋.

/**

*Maximumnumberofthingsperpane.

*@type{number}

*/

project.MyCtotype.someProperty=4;E.類型轉換的注釋有時,類型檢查不能很準確地推斷出表達式的類型,所以應該給它添加類型標記注釋來明確之,并且必須在表達式和類型標簽外面包裹括號.

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

(/**@type{number}*/x)F.JSDoc縮進如果你在@param,@return,@supported,@this或@deprecated中斷行,需要像在代碼中一樣,使用4個空格作為一個縮進層次.

/**

*Illustrateslinewrappingforlongparam/returndescriptions.

*@param{string}fooThisisaparamwithadescriptiontoolongtofitin

*

oneline.

*@return{number}Thisreturnssomethingthathasadescriptiontoolongto

*

fitinoneline.

*/

project.MyCtotype.method=function(foo){

return5;

};不要在@標記中進行縮進.雖然不建議,但也可對說明文字進行適當的排版對齊.不過,這樣帶來一些負面影響,就是當你每次修改變量名時,都得重新排版說明文字以保持和變量名對齊./**

*ThisisNOTthepreferredindentationmethod.

*@param{string}fooThisisaparamwithadescriptiontoolongtofitin

*

oneline.

*@return{number}Thisreturnssomethingthathasadescriptiontoolongto

*

fitinoneline.

*/

project.MyCtotype.method=function(foo){

return5;

};枚舉/**

*Enumfortri-statevalues.

*@enum{number}

*/

project.TriState={

TRUE:1,

FALSE:-1,

MAYBE:0

};

注意一下,枚舉也具有有效類型,所以可以當成參數類型來用.

/**

*Setsprojectstate.

*@param{project.TriState}stateNewprojectstate.

*/

project.setState=function(state){

//...

};G.Typedefs有時類型會很復雜.比如下面的函數,接收Element參數:

/**

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

...

};H.JSDoc標記表標記模板&例子描述類型檢測支持@param@param{Type}變量名描述如:/**

*QueriesaBazforitems.

*@param{number}groupNumSubgroupidtoquery.

*@param{string|number|null}termAnitemName,

*oritemId,ornulltosearcheverything.

*/

goog.Btotype.query=function(groupNum,term){

//...

};給方法,函數,構造器中的參數添加說明.完全支持.@return@return{Type}描述如:/**

*@return{string}ThehexIDofthelastitem.

*/

goog.Btotype.getLastId=function(){

//...

returnid;

};給方法,函數的返回值添加說明.在描述布爾型參數時,用"Whetherthecomponentisvisible"這種描述優(yōu)于"Trueifthecomponentisvisible,falseotherwise".如果函數沒有返回值,就不需要添加@return標記.完全支持.@author@authorusername@(firstlast)如:/**

*@Utilitiesforhandlingtextareas.

*@authorkuth@(UthurPendragon)

*/表明文件的作者,通常僅會在@注釋中使用到它.不需要.@see@seeLink如:/**

*Addsasingleitem,recklessly.

*@see#addSafely

*@seegoog.Collect

*@seegoog.RecklessAdder#add

...給出引用鏈接,用于進一步查看函數/方法的相關細節(jié).不需要.@@描述如:/**

*@Utilitiesfordoingthingsthatrequirethisverylong

*butnotindentedcomment.

*@authorkuth@(UthurPendragon)

*/文件通覽.不需要.@constructor@constructor如:/**

*Arectangle.

*@constructor

*/

functionGM_Rect(){

...

}指明類中的構造器.會檢查.如果省略了,編譯器將禁止實例化.@interface@interface如:/**

*Ashape.

*@interface

*/

functionShape(){};

Stotype.draw=function(){};

/**

*Apolygon.

*@interface

*@extends{Shape}

*/

functionPolygon(){};

Ptotype.getSides=function(){};指明這個函數是一個接口.會檢查.如果實例化一個接口,編譯器會警告.@type@typeType

@type{Type}如:/**

*ThemessagehexID.

*@type{string}

*/

varhexId=hexId;標識變量,屬性或表達式的類型.大多數類型是不需要加大括號的,但為了保持一致,建議統(tǒng)一加大括號.會檢查@extends@extendsType

@extends{Type}如:/**

*Immutableemptynodelist.

*@constructor

*@extendsgoog.ds.BasicNodeList

*/

goog.ds.EmptyNodeList=function(){

...

};與@constructor一起使用,用來表明該類是擴展自其它類的.類型外的大括號可寫可不寫.會檢查@implements@implementsType

@implements{Type}如:/**

*Ashape.

*@interface

*/

functionShape(){};

Stotype.draw=function(){};

/**

*@constructor

*@implements{Shape}

*/

functionSquare(){};

Stotype.draw=function(){

...

};與@constructor一起使用,用來表明該類實現(xiàn)自一個接口.類型外的大括號可寫可不寫.會檢查.如果接口不完整,編譯器會警告.@lends@lendsobjectName

@lends{objectName}如:goog.object.extend(

Btotype,

/**@lends{Btotype}*/

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論