国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
[轉(zhuǎn)]JavaScript的陷阱

版權(quán)聲明

:轉(zhuǎn)載時請以超鏈接形式標明文章原始出處和作者信息及本聲明

http://monw3c.blogbus.com/logs/31056019.html

這本來是翻譯Estelle Weyl的《15 JavaScript Gotchas》

,里面介紹的都是在JavaScript編程實踐中平時容易出錯或需要注意的地方,并提供避開這些陷阱的方法,總體上講,就是在認清事物本質(zhì)的基礎(chǔ)樣要堅持好的編程習慣,其實這就是Douglas Crockford很久以前提出的JavaScript風格要素問題了,有些內(nèi)容直接是相同的,具體請看《Javascript風格要素(1)》
《Javascript風格要素(2)》
。在翻譯的過程中,我又看到了賢安去年翻譯的《JavaScript的9個陷阱及評點》
,其內(nèi)容又有些交叉在一起,所以我就在現(xiàn)有翻譯的基礎(chǔ)上做了一個簡單的拼合,并依據(jù)自己的理解增加了一些注釋和解釋。

  1. 區(qū)分大小寫:變量名、屬性和方法全部都區(qū)分大小寫
  2. 不匹配的引號、圓括號或花括號將拋出錯誤
  3. 條件語句:3個常見陷阱
  4. 換行:一直用分號結(jié)束語句來避免常見的換行問題
  5. 標點法:在對象聲明的尾部逗號將導(dǎo)致出錯
  6. HTML id 沖突
  7. 變量作用域:全局變量對局部變量
  8. 函數(shù)重載:當重載不存在時,覆蓋函數(shù)
  9. 區(qū)分string.replace()函數(shù)不是全局的
  10. parseInt應(yīng)該包含兩個參數(shù)
  11. “this”和綁定問題
  12. 為參數(shù)設(shè)置默認值,以免你遺漏它們
  13. for each循環(huán)是用于對象而不是數(shù)組
  14. switch語句需要點技巧
  15. 如果你要檢查null,應(yīng)該先檢查undefined
  16. 時間處理陷阱

區(qū)分大小寫

變量名和函數(shù)名都是區(qū)分大小寫的。就像配錯的引號一樣,這些大家都知道。但是,由于錯誤是不作聲的,所以這是一個提醒。為自己選擇一個命名規(guī)則,并堅持它。而且,記住JavaScript中的原生函數(shù)和CSS屬性都是駱駝拼寫法(camelCase)

。

getElementById(’myId’) != getElementByID(’myId’); //它應(yīng)該是“Id”而不是“ID”getElementById(’myId‘) != getElementById(’myID‘); // “Id”也不等于“ID”document.getElementById('myId').style.Color; //返回 "undefined"

不匹配的引號、圓括號或花括號

避免陷入不匹配的引號、圓括號或花括號陷阱的最好方式是編碼時一直同時寫出打開和關(guān)閉這兩個元素符號,然后在其中間加入代碼。開始:

var myString = ""; //在輸入字符串值之前寫入這對引號function myFunction(){if(){//關(guān)閉每個打開的括弧}}//統(tǒng)計所有的左括號和右括號數(shù)量,并且確保它們相等alert(parseInt(var1)*(parseInt(var2)+parseInt(var3))); //關(guān)閉每個打開的圓括號

每當你打開一個元素,請關(guān)閉它。當你添加了關(guān)閉圓括號后,你再把函數(shù)的參數(shù)放進圓括號中。如果有一串圓括號,統(tǒng)計所有打開的圓括號和所有關(guān)閉的圓括號,并且確保這兩個數(shù)字相等。

條件語句(3個陷阱)

  1. 所有的條件語句都必須位于圓括號中。執(zhí)行語句主體不管是一句還是多句都強烈建議用花括號包圍起來,這樣能避免很多因修改或嵌套而產(chǎn)生的潛在錯誤。
    if(var1 == var2){//statement}
  2. 不要犯無意地使用賦值運算符的錯誤:把第二個參數(shù)的值賦給第一個參數(shù)。因為它是一個邏輯問題,它將一直返回true且不會報錯。
    if(var1 = var2){} // 返回true。把var2賦值給var1
  3. JavaScript是弱類型,除了在switch語句
    中。當JavaScript在case比較時,它是非弱類型。
    var myVar = 5;    if(myVar == '5'){ //返回true,因為JavaScript是弱類型    alert("hi");  //這個alert將執(zhí)行,因為JavaScript通常不在意數(shù)據(jù)類型    }    switch(myVar){    case '5':    alert("hi"); //這個alert將不會執(zhí)行,因為數(shù)據(jù)類型不匹配    }    

換行

當心JavaScript中的硬換行。換行被解釋為表示行結(jié)束的分號。即使在字符串中,如果在引號中包括了一個硬換行,那么你會得到一個解析錯誤(未結(jié)束的字符串)。

var bad  = '<ul id="myId"><li>some text</li><li>more text</li></ul>'; // 未結(jié)束的字符串錯誤var good = '<ul id="myId">' +‘<li>some text</li>‘ +‘<li>more text</li>‘ +‘</ul>’; // 正確

前面討論過的換行被解釋為分號的規(guī)則并不適用于控制結(jié)構(gòu)這種情況:條件語句關(guān)閉圓括號后的換行并不是給其一個分號。

一直使用分號和圓括號,那么你不會因換行而出錯,你的代碼易于閱讀,且除了那些不使用分號的怪異源碼外你會少一些顧慮:所以當移動代碼且最終導(dǎo)致兩個語句在一行時,你無需擔心第一個語句是否正確結(jié)束。

多余的逗號

在任何JavaScript對象定義中,最后一個屬性決不能以一個逗號結(jié)尾。Firefox不會出錯,而IE會報語法錯誤。

var theObj = {city : "Boston",state : "MA",//IE6和IE7中有“缺少標識符、字符串或數(shù)字”的錯誤,IE8 beta2修正了它}

HTML id 沖突

JavaScript DOM綁定(JavaScript DOM bindings)

允許通過HTML id索引。在JavaScript中函數(shù)和屬性共享同一個名字空間。所以,當在HTML中的一個id和函數(shù)或?qū)傩杂邢嗤拿謺r,你會得到難以跟蹤的邏輯錯誤。然而這更多是一個CSS最佳實踐
的問題,當你不能解決你的JavaScript問題時,想起它是很重要的。

<ul><li id="length">1</li><li id="thisLength">2</li><li id="thatLength">3</li></ul><script>var listitems = document.getElementsByTagName('li');var liCount = listitems.length; //IE下返回的是<li id="length">1</li>這個節(jié)點而不是所有<li的數(shù)量var thisLength = document.getElementById('thisLength');thatLength = document.getElementById('thatLength');//IE下會出現(xiàn)“對象不支持此屬性和方法”的錯誤,IE8 beta2下首次加載頁面會出錯,刷新頁面則不會//在IE中thisLength和thatLength直接表示以其為id值的DOM節(jié)點,//所以賦值時會出錯,當有var聲明時,IE會把其當著變量,這個時候就正常了。</script>

如果你要標記(X)HTML,絕不要使用JavaScript方法或?qū)傩悦鳛閕d的值。并且,當你寫JavaScript時,避免使用 (X)HTML中的id值作為變量名。

變量作用域

JavaScript中的許多問題都來自于變量作用域:要么認為局部變量是全局的,要么用函數(shù)中的局部變量覆蓋了全局變量。為了避免這些問題,最佳方案是根本沒有任何全局變量。但是,如果你有一堆,那么你應(yīng)該知道這些陷阱。

不用var關(guān)鍵字聲明的變量是全局的。記住使用var關(guān)鍵字聲明變量,防止變量具有全局作用域。在下面例子中,在函數(shù)中聲明的變量具有全局變量,因為沒有使用var關(guān)鍵字聲明:

anonymousFuntion1 = function(){globalvar = 'global scope'; //全局聲明,因為“var”遺漏了return localvar;}();alert(globalvar); //彈出“global scope”,因為函數(shù)中的變量是全局聲明anonymousFuntion2 = function(){var localvar = 'local scope'; //使用“var”局部聲明return localvar;}();alert(localvar); //錯誤 “localvar未定義”。沒有全局定義localvar

作為參數(shù)引進到函數(shù)的變量名是局部的。如果參數(shù)名也是一個全局變量的名字,像參數(shù)變量一樣有局部作用域,這沒有沖突。如果你想在函數(shù)中改變一個全局變量,這個函數(shù)有一個參數(shù)復(fù)制于這個全局變量名,記住所有全局變臉都是window對象的屬性。

var myscope = "global";function showScope(myscope){return myscope; //局部作用域,即使有一個相同名字的全局變量}alert(showScope('local'));function globalScope(myscope){myscope = window.myscope; //全局作用域return myscope;}alert(globalScope(’local’));

你甚至可以在循環(huán)中聲明變量:

for(var i = 0; i < myarray.length; i++){}

覆蓋函數(shù)/重載函數(shù)

當你不止一次的聲明一個函數(shù)時,這個函數(shù)的最后一次聲明將覆蓋掉該函數(shù)的所有前面版本且不會拋出任何錯誤或警告。這不同于其他的編程語言,像Java,你能用相同的名字有多重函數(shù),只要它們有不同的參數(shù):調(diào)用函數(shù)重載。在JavaScript中沒有重載。這使得不能在代碼中使用JavaScript核心部分的名字極其重要。也要當心包含的多個JavaScript文件,像一個包含的腳本文件可能覆蓋另一個腳本文件中的函數(shù)。請使用匿名函數(shù)和名字空間。

(function(){// creation of my namespace 創(chuàng)建我的名字空間if(!window.MYNAMESPACE) {window['MYNAMESPACE'] = {};}//如果名字空間不存在,就創(chuàng)建它//這個函數(shù)僅能在匿名函數(shù)中訪問function myFunction(var1, var2){//內(nèi)部的函數(shù)代碼在這兒}// 把內(nèi)部函數(shù)連接到名字空間上,使它通過使用名字空間能訪問匿名函數(shù)的外面 window['MYNAMESPACE']['myFunction'] = myFunction;})(); // 圓括號 = 立即執(zhí)行// 包含所有代碼的圓括號使函數(shù)匿名

這個例子正式為了實現(xiàn)解決上一個陷阱“變量作用域”的最佳方案。匿名函數(shù)詳細內(nèi)容請看《Javascript的匿名函數(shù)》

。YUI
整個庫只有YAHOO和YAHOO_config兩個全局變量,它正是大量應(yīng)用匿名函數(shù)和命名空間的方法來實現(xiàn),具體請看《Javascript的一種模塊模式》

字符串替換

一個常見錯誤是假設(shè)字符串替換方法的行為會對所有可能匹配都產(chǎn)生影響。實際上,JavaScript字符串替換只改變了第一次發(fā)生的地方。為了替換所有發(fā)生的地方,你需要設(shè)置全局標識。同時需要記住String.replace()的第一個參數(shù)是一個正則表達式。

var myString = "this is my string";myString = myString.replace("","%20"); // "this%20is my string"myString = myString.replace(/ /,"%20"); // "this%20is my string"myString = myString.replace(/ /g,"%20"); // "this%20is%20my%20string"

parseInt

在JavaScript得到整數(shù)的最常見錯誤是假設(shè)parseInt返回的整數(shù)是基于10進制的。別忘記第二個參數(shù)基數(shù),它能是從2到36之間的任何值。為了確保你不會弄錯,請一直包含第二個參數(shù)。

parseInt('09/10/08'); //0parseInt(’09/10/08′,10); //9, 它最可能是你想從一個日期中得到的值

如果parseInt沒有提供第二個參數(shù),則前綴為 ‘0x’ 的字符串被當作十六進制,前綴為 ‘0′ 的字符串被當作八進制。所有其它字符串都被當作是十進制的。如果 numString 的前綴不能解釋為整數(shù),則返回 NaN(而不是數(shù)字)。

‘this’

另一個常見的錯誤是忘記使用“this”。在JavaScript對象中定義的函數(shù)訪問這個對象的屬性,但沒有使用引用標識符“this”。例如,下面是錯誤的:

function myFunction() {var myObject = {objProperty: "some text",objMethod: function() {alert(objProperty);}};myObject.objMethod();}function myFunction() {var myObject = {objProperty: "some text",objMethod: function() {alert(this.objProperty);}};myObject.objMethod();}

有一篇A List Apart文章

用通俗易懂的英文表達了this綁定的問題。

對this使用最大的陷阱是this在使用過程中其引用會發(fā)生改變:

<input type="button" value="Gotcha!" id="MyButton"><script>var MyObject = function () {this.alertMessage = "Javascript rules";this.ClickHandler = function() {alert(this.alertMessage );//返回結(jié)果不是”JavaScript rules”,執(zhí)行MyObject.ClickHandler時,//this的引用實際上指向的是document.getElementById("theText")的引用}}();document.getElementById(”theText”).onclick =  MyObject.ClickHandler</script>

其解決方案是:

var MyObject = function () {var self = this;this.alertMessage = “Javascript rules”;this.OnClick = function() {alert(self.value);}}();

類似問題的更多細節(jié)和解決方案請看《JavaScript作用域的問題》

。

遺漏的參數(shù)

當給函數(shù)增加一個參數(shù)時,一個常見的錯誤是忘記更新這個函數(shù)的所有調(diào)用。如果你需要在已經(jīng)被調(diào)用的函數(shù)中增加一個參數(shù)來處理一個特殊情況下的調(diào)用,請給這個函數(shù)中的這個參數(shù)設(shè)置默認值,以防萬一在眾多腳本中的眾多調(diào)用中的一個忘記更新。

function addressFunction(address, city, state, country){country = country || “US”; //如果沒有傳入country,假設(shè) “US”span>//剩下代碼}

你也能通過獲取arguments來解決。但是在這篇文章我們的注意力在陷阱上。同時在《Javascript風格要素(2)》

也介紹了||巧妙應(yīng)用。

for關(guān)鍵字

在JavaScript中關(guān)鍵字for有兩種使用方式,一個是for語句,一個是for/in語句。for/in語句將遍歷所有的對象屬性(attribute),包括方法和屬性(property)。決不能使用for/in來遍歷數(shù)組:僅在當需要遍歷對象屬性和方法時才使用for/in。

  1. for(var myVar in myObject)語句用一個指定變量無任何規(guī)律地遍歷對象的所有屬性。如果for/in循環(huán)的主體刪除了一個還沒有枚舉出的屬性,那么該屬性就不在枚舉。如果循環(huán)主體定義了新屬性,那么循環(huán)是否枚舉該屬性則是由JavaScript的實現(xiàn)決定。
  2. for(var 1=0; i < myArray.length; i++)語句會遍歷完一個數(shù)組的所有元素。

為了解決這個問題,大體上你可以對對象使用 for … in,對數(shù)組使用for循環(huán):

listItems = document.getElementsByTagName('li');for (var listitem in listItems){//這里將遍歷這個對象的所有屬性和方法,包括原生的方法和屬性,但不遍歷這個數(shù)組:出錯了!}//因為你要循環(huán)的是數(shù)組對象,所用for循環(huán)for ( var i = 0; i < listItems.length; i++) {//這是真正你想要的}

對象的有些屬性以相同的方式標記成只讀的、永久的或不可列舉的,這些屬性for/in無法枚舉。實際上,for/in循環(huán)
會遍歷所有對象的所有可能屬性,包括函數(shù)和原型中的屬性。所有修改原型屬性可能對for/in循環(huán)帶來致命的危害,所以需要采用hasOwnProperty和typeof做一些必要的過濾,最好是用for來代替for/in。

switch語句

Estelle Weyl寫了一篇switch statement quirks

,其要點是:

  1. 沒有數(shù)據(jù)類型轉(zhuǎn)換
  2. 一個匹配,所有的表達式都將執(zhí)行直到后面的break或return語句執(zhí)行
  3. 你可以對一個單獨語句塊使用多個case從句

undefined ≠ null

null是一個對象,undefined是一個屬性、方法或變量。存在null是因為對象被定義。如果對象沒有被定義,而測試它是否是null,但因為沒有被定義,它無法測試到,而且會拋出錯誤。

if(myObject !== null  && typeof(myObject) !== 'undefined') {//如果myObject是undefined,它不能測試是否為null,而且還會拋出錯誤}if(typeof(myObject) !== 'undefined' && myObject !== null) {//處理myObject的代碼}

Harish Mallipeddi

對undefined和null有一個說明。

事件處理陷阱

剛接觸事件處理時最常見的寫法就是類似:

window.onclick = MyOnClickMethod

這種做法不僅非常容易出現(xiàn)后面的window.onclick事件覆蓋掉前面的事件,還可能導(dǎo)致大名頂頂?shù)腎E內(nèi)存泄露問題。為了解決類似問題,4年前Simon Willison

就寫出了很流行的addLoadEvent():

function addLoadEvent(func) {var oldonload = window.onload;if (typeof window.onload != 'function') {window.onload = func;}else {window.onload = function() {oldonload();unc();}}}addEvent(window,'load',func1,false);addEvent(window,'load',func2,false);addEvent(window,'load',func3,false);

當然在JavaScript庫盛行的現(xiàn)在,使用封裝好的事件處理機制是一個很好的選擇,比如在YUI中就可以這樣寫:

YAHOO.util.Event.addListener(window, "click", MyOnClickMethod);
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服