天天看點

JavaScript的9個陷阱及評點 http://realazy.org/blog/2007/08/20/nine-javascript-gotchas/

http://realazy.org/blog/2007/08/20/nine-javascript-gotchas/

來自Nine Javascript Gotchas, 以下是JavaScript容易犯錯的九個陷阱。雖然不是什麼很高深的技術問題,但注意一下,會使您的程式設計輕松些,即所謂make life easier. 筆者對某些陷阱會混雜一些評點。

  1. 最後一個逗号

    如這段代碼,注意最後一個逗号,按語言學角度來說應該是不錯的(python的類似資料類型辭典dictionary就允許如此)。IE會報文法錯誤,但語焉不詳,你隻能用人眼從幾千行代碼中掃描。
    <script>
      var theObj = {
            city : "Boston",
            state : "MA",
      }
    </script> 
               
  2. this

    的引用會改變

    如這段代碼:
    <input type="button" value="Gotcha!" id="MyButton" >
    <script>
    var MyObject = function () {
        this.alertMessage = "Javascript rules";
        this.ClickHandler = function() {
            alert(this.alertMessage );
      }
    }();
    document.getElementById("theText").onclick =  MyObject.ClickHandler
    </script>
               
    并不如你所願,答案并不是”JavaScript rules”。在執行

    MyObject.ClickHandler

    時,代碼中紅色這行,

    this

    的引用實際上指向的是

    document.getElementById("theText")

    的引用。可以這麼解決:
    <input type="button" value="Gotcha!" id="theText" >
    <script>
    var MyObject = function () {
        var self = this;                
        this.alertMessage = "Javascript rules";
        this.OnClick = function() {
            alert(self.value);
        }
    }();
    document.getElementById("theText").onclick =  MyObject.OnClick
    </script>      
    實質上,這就是JavaScript作用域的問題。如果你看過,你會發現解決方案不止一種。
  3. 辨別盜賊

    在JavaScript中不要使用跟HTML的id一樣的變量名。如下代碼:
    <input type="button" id="TheButton">
    <script>
        TheButton = get("TheButton");
    </script>
               
    IE會報對象未定義的錯誤。我隻能說:IE sucks.
  4. 字元串隻替換第一個比對

    如下代碼:
    <script>
        var fileName = "This is a title".replace(" ","_");
    </script>
               
    而實際上,結果是”

    This_is a title

    “. 在JavaScript中,

    String.replace

    的第一個參數應該是正規表達式。是以,正确的做法是這樣:
    var fileName = "This is a title".replace(/ /g,"_");
               
  5. mouseout意味着mousein

    事實上,這是由于事件冒泡導緻的。IE中有

    mouseenter

    mouseleave

    ,但不是标準的。作者在此建議大家使用庫比如YUI來解決問題。
  6. parseInt

    是基于進制體系的

    這個是常識,可是很多人給忽略了

    parseInt

    還有第二個參數,用以指明進制。比如,

    parseInt("09")

    ,如果你認為答案是9,那就錯了。因為,在此,字元串以0開頭,

    parseInt

    以八進制來處理它,在八進制中,

    09

    是非法,傳回

    false

    ,布爾值

    false

    轉化成數值就是0. 是以,正确的做法是

    parseInt("09", 10)

    .
  7. for...in...

    會周遊所有的東西

    有一段這樣的代碼:
    var arr = [5,10,15]
    var total = 1;
    for ( var x in arr) {
        total = total * arr[x];
    }
               
    運作得好好的,不是嗎?但是有一天它不幹了,給我傳回的值變成了

    NaN

    , 暈。我隻不過引入了一個庫而已啊。原來是這個庫改寫了

    Array

    prototype

    ,這樣,我們的

    arr

    平白無過多出了一個屬性(方法),而

    for...in...

    會把它給周遊出來。是以這樣做才是比較安全的:
    for ( var x = 0; x < arr.length; x++) {
        total = total * arr[x];
    }
               
    其實,這也是污染基本類的

    prototype

    會帶來危害的一個例證。
  8. 事件處理器的陷阱

    這其實隻會存在使用作為對象屬性的事件處理器才會存在的問題。比如

    window.onclick = MyOnClickMethod

    這樣的代碼,這會複寫掉之前的

    window.onclick

    事件,還可能導緻IE的内容洩露(sucks again)。在IE還沒有支援DOM 2的事件注冊之前,作者建議使用庫來解決問題,比如使用YUI:
    YAHOO.util.Event.addListener(window, "click", MyOnClickMethod);
               
    這應該也屬于常識問題,但新手可能容易犯錯。
  9. Focus Pocus

    建立一個

    input

    文本元素,然後把焦點挪到它上面,按理說,這樣的代碼應該很自然:
    var newInput = document.createElement("input");
    document.body.appendChild(newInput);
    newInput.focus();
    newInput.select();
               
    但是IE會報錯(sucks again and again)。理由可能是當你執行

    fouce()

    的時候,元素尚未可用。是以,我們可以延遲執行:
    var newInput = document.createElement("input");
    newInput.id = "TheNewInput";
    document.body.appendChild(newInput);
    setTimeout(function(){ //這裡我使用閉包改寫過,若有興趣可以對比原文
    	document.getElementById('TheNewInput').focus();
    	document.getElementById('TheNewInput').select();}, 10);
               

在實踐中,JavaScript的陷阱還有很多很多,大多是由于解析器的實作不到位而引起。這些東西一般都不會在教科書中出現,隻能靠開發者之間的經驗分享。謝天謝地,我們生活在網絡時代,很多碰到的問題,一般都可以在Google中找到答案。

This entry was postedon Monday, August 20th, 2007 at 02:31 and is filed under JS / Dom.You can follow any responses to this entry through the RSS 2.0 feed.You can leave a response, or trackback from your own site.

21 Responses to “JavaScript的9個陷阱及評點”

  1. Cloudream Says:

    August 20th, 2007 at 03:32

    那個親愛的IE……

    -_,-

    當然Firefox也有JS處理問題……OPERA同樣也不完美……

    (偶承認,偶記不知他們仨HTML解析核心的名字……除了gecko……)

    (○ ̄ ~  ̄○)

  2. jaceju Says:

    August 20th, 2007 at 09:56

    譯得好!

    不過為什麼標題是 “Scrip” ?是不是少了個 t ?

    JavaScript的9個陷阱及評點 http://realazy.org/blog/2007/08/20/nine-javascript-gotchas/
  3. 子烏 Says:

    August 20th, 2007 at 10:53

    嗯,其實這些也并不算是陷阱,隻能算是js初學者容易犯的幾個錯誤:D

  4. ÀÖÀÖ˶ Says:

    August 20th, 2007 at 11:32

    JavaScripµÄ9¸ö……

    À´×ÔNine Javascript Gotchas, ÒÔÏÂÊÇJavaScriptÈÝÒ×·¸´íµÄ¾Å¸öÏÝÚå¡£ËäÈ»²»ÊÇʲôºÜ¸ßÉîµÄ¼¼ÊõÎÊÌ⣬µ«×¢Òâһϣ¬»áʹÄúµÄ±à³ÌÇáËÉЩ£¬¼´Ëùνmake life easier. ±…

  5. cute Says:

    August 20th, 2007 at 14:26

    都是常犯錯誤。

  6. 沈蚊 Says:

    August 21st, 2007 at 00:03

    亞黑的英文真不是一般難看。

  7. 魏中華 Says:

    August 21st, 2007 at 11:12

    大緻看了下 YUI,驚歎于它龐大的規模,幾十個檔案夾,動辄數千行,莫非是傳說中的 Javascript 版本的 MFC ?

    像我這種對複雜事物特别敏感的人士,似乎很難感興趣,看來要抱憾終生了。

  8. kakawar Says:

    August 21st, 2007 at 13:27

    我覺得jQuery也挺好,因為目前隻會用這個……

  9. hax Says:

    August 21st, 2007 at 18:04

    你的譯文與原文有點不一樣。有些你的評點應該說明一下,不是原文的。

    “理由可能是當你執行fouce()的時候,元素還不存在。”

    這裡你寫錯了。一個是筆誤,另外一個,元素當然已經存在了。原文說的是not available,不可用而已。

  10. hax Says:

    August 21st, 2007 at 18:10

    To Cloudream:

    ie的引擎叫做Trident,三叉戟。

    opera似乎沒有專門的名字。

    safari是WebCore。

    它們的js引擎分别是:

    JScript (IE)

    SpiderMonkey(FF)

    JavaScriptCore(Safari)

    linear_b(Opera)

  11. yason Says:

    August 27th, 2007 at 18:00

    确實非常不錯的内容

  12. superwunc Says:

    September 3rd, 2007 at 09:54

    關于第三個陷阱

    如果對變量使用var定義了就不會有問題

    var TheButton ;

    TheButton = get(“TheButton”);

  13. fyting Says:

    September 8th, 2007 at 15:42

    用了好幾個suck,我剛開始以為原文如此,結果發現是你翻譯時把自己的個人喜好也加進去了。

    This will work fine in Firefox but cause and object undefined error in Internet Explorer

    IE會報對象未定義的錯誤。我隻能說:IE sucks.

  14. aw Says:

    October 1st, 2007 at 21:30

    關于Prototype确實很惡心。用ActionScript2就很爽 ^_^

    話說我當年剛開始寫AS的時候,滿眼望去都是Prototype……一個個都是地雷啊!

  15. popper Says:

    October 8th, 2007 at 08:58

    正在學習 中 數于初學着感覺還是很有幫助的 。

  16. Akira Says:

    November 3rd, 2007 at 11:18

    我也來評一下^^

    最後一個逗号

    如這段代碼,注意最後一個逗号,按語言學角度來說應該是不錯的(python的類似資料類型辭典dictionary就允許如此)。IE會報文法錯誤,但語焉不詳,你隻能用人眼從幾千行代碼中掃描。

    ————————————————————————————————————————-

    這是JS解析器的問題,符合ECMA v3文法規範

    這不算一個毛病,追求這個未免有點太……

    允許最後一個逗号或許有好處,但是這樣的話,不利于判斷對象的結束,不認真的話也會産生問題

    (舉一個可能不是十分恰當的例子:應該沒有人指責C語言字元串中的最後一個”)

    this的引用會改變

    ————————————————————————————————————————-

    對于習慣了Class-based OOP的人來說這是一個大問題

    this指針怎麼應該改變呢,我也認為不應該

    但是JavaScript不是Class-based OOP的語言,而且,更重要的是

    它的this是在執行域生效,而不是在文法域生效

    JS的函數是可以作為資料來對待的,是以this隻表示執行域上的對象所有者

    這很讓人困擾,但是也有好處,好處之一是泛型,這裡我不過多作解釋,需要了解一些進階的概念

    辨別盜賊

    在JavaScript中不要使用跟HTML的id一樣的變量名。如下代碼:

    —————————————————————————————————————–

    這個完全不是問題,W3C的規範中DOM對象通過document.getElementById來獲得

    它不應該和JS的變量沖突,如果沖突了是浏覽器的問題

    例子中的問題加上var就可以避免

    字元串隻替換第一個比對

    —————————————————————————————————————-

    想不出這個為什麼也算問題,或許應該把replace函數分成replaceFirst和replaceAll(笑)

    mouseout意味着mousein

    事實上,這是由于事件冒泡導緻的。IE中有mouseenter和mouseleave,但不是标準的。作者在此建議大家使用庫比如YUI來解決問題。

    —————————————————————————————————————-

    IE的事件模型,讨厭的相容性,交給基礎庫去處理

    parseInt是基于進制體系的

    這個是常識,可是很多人給忽略了parseInt還有第二個參數,用以指明進制。比如,parseInt(“09″),如果你認為答案是9,那就錯了。因為,在此,字元串以0開頭,parseInt以八進制來處理它,在八進制中,09是非法,傳回false,布爾值false轉化成數值就是0. 是以,正确的做法是parseInt(“09″, 10).

    ————————————————————————————————–

    嗯,是啊……C語言的atoi會不會這樣?(笑)

    for…in…會周遊所有的東西

    ————————————————————————————————-

    應該是會周遊所有propertyIsEnumerable的東西

    是以強烈BS直接修改Object原型的做法

    但是數組也不應該用for…in…來周遊,那不符合語義

    事件處理器的陷阱

    這其實隻會存在使用作為對象屬性的事件處理器才會存在的問題。比如window.onclick = MyOnClickMethod這樣的代碼,這會複寫掉之前的window.onclick事件,還可能導緻IE的内容洩露(sucks again)。在IE還沒有支援DOM 2的事件注冊之前,作者建議使用庫來解決問題,比如使用YUI:

    —————————————————————————————————–

    嗯,事件模型很令人頭疼……

    但是IE用attachEvent可以避免這個問題

    Focus Pocus

    建立一個input文本元素,然後把焦點挪到它上面,按理說,這樣的代碼應該很自然:

    —————————————————————————————————-

    這個……沒辦法……

    還是事先做好一個hidden的input然後show出來吧

    那樣也可以快一些

  17. 貓魚 Says:

    November 29th, 2007 at 17:53

    請問為何 第一個例子裡面的

    MyObject.ClickHandler

    ie總會報錯: MyObject.ClickHandler為空或不是對象?

  18. weiye Says:

    December 20th, 2007 at 23:49

    關于this的問題,樓主的例子是有問題的,

    var MyObject = function () {

    var self = this;

    this.alertMessage = “Javascript rules”;

    this.OnClick = function() {

    alert(self.value);

    }

    }();

    document.getElementById(”theText”).onclick = MyObject.OnClick

    第一個匿名函數的實際調用對象是window,self=this=window。匿名函數調用的結果傳回給MyObjct。它并不具有方法OnClick,OnClick實際是賦給了window。

    可以改成這樣

    function MyObject () {

    this.alertMessage = “Javascript rules”;

    this.OnClick = function() {

    alert(self.value);

    }

    };

    MyObject.call(MyObject);

    document.getElementById(”theText”).onclick = MyObject.OnClick

    ————————————————————————————————————

    第三個在JavaScript中不要使用跟HTML的id一樣的變量名。這根本不是問題。

    IE會把id當作dom對象,當然不可以随意指派,使用的時候應該重新定義 TheButton = get(“TheButton”);就像不能直接給self指派一樣,self本身指向window對象。

  19. 飛天大神豬 Says:

    January 8th, 2008 at 09:19

    确實是遇到過裡面的一些問題。但不贊成遇到問題随便使用類庫來解決。因為你永遠不知道類庫會帶來什麼後果。

  20. JavaScript的9個陷阱 - Elric’s Blog - 關注前端技術,關注生活. Says:

    June 17th, 2009 at 09:17

    [...] 譯文:http://realazy.org/blog/2007/08/20/nine-javascript-gotchas/ 日志分類:Javascript 标簽:Javascript [...]

  21. Physure.com » [轉]JavaScript的陷阱 Says:

    February 6th, 2010 at 00:16

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

繼續閱讀