2007年08月17日 01:15 [Edit]

怠翻 - JavaScriptでありがちな9つのシマッタ

私自身結構シマッタしちゃうので。


  1. 尻カンマ注意

    以下のコードはFireFoxでは動きますが、Internet Explorer (以下IE)では問題になります。

      var theObj = {
            city : "Boston",
            state : "MA",
      }
    

    最後にカンマが入らないよう注意しましょう。

  2. 浮気なthisは何を見てるやら

    以下のコードで、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>
    

    これは、ClickHandler()がどう呼ばれたかによって変わってしまいます。MyObject.OnClick()を呼べば"Javascript rules"が表示されるのに、MyButtonをクリックしても"undefined"としか表示されません。これを防ぐには、以下のようにthisをローカル変数に保存して、それを渡すようにします。

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

    var selfvarをくれぐれもお忘れなく。

  3. 身元詐称

    グローバル変数名とHTMLのIDが重ならないよう注意しましょう。

    <input type="button" id="TheButton">
    <script>
        TheButton = get("TheButton");
    </script>
    

    Fifefoxでは問題ありませんが、IEでは未定義オブジェクトエラーが出てしまいます。

  4. 文字列置換で最初のマッチしか置換されない
         var fileName = "This is a title".replace(" ","_");
    

    結果は"This_is a title"。これが期待した結果ならいいのですが、全部置換した場合には、gを指定しなければなりません。

        var fileName = "This is a title".replace(/ /g,"_");
    
  5. MouseOutがMouseInになったり

    ブロック要素が重なった場合、ある要素におけるMouseOutがその外の要素のMouseInになったりして大変ややこしいことになったりします。とくにコンテキストメニューを実装する場合などにそうなったりします。

    これを防ぐ一番簡単な方法は、YUIなど専用ライブラリを使うことです。

  6. ParseIntのしゃっくりを止める

    ParseInt()は使えます。文字列の中に、数字以外のものが入っていても期待どおりに動きます。例えばこんな風に。

    var height = parseInt("200px")
    

    ところが、数字の頭に0がついていると、ParseInt()は問答無用でそれを8進数として扱います。以下のような場合、それは困ります。

        month = "09"
        var monthInt = parseInt(month) // 9でなくて0
    

    この場合でも、基数を指定してやることで、10進法を強制することが出来ます。

      var monthInt = parseInt(month , 10);
    
  7. まわりすぎなforループ
    var arr = [5,10,15]
    var total = 1;
    for (var x in arr) {
        total = total * arr[x];
    }
    

    これでarrの中身を全てかけ算できるはずですが、"NaN"が出てきてしった時にはまいりました。arrにたとえばmyfunc()といった関数オブジェクトまで入っていると、それまでforループで代入されてしまうのがその原因でした。

    配列は以下のようにきちんとまわしましょう。

    for (var x = 0; x < arr.length; x++) {
        total = total * arr[x];
    }
    

    あるいは、

    for (var x = 0, l = arr.length; x < l; x++) {
        total = total * arr[x];
    }
    
  8. イベントハンドラの落とし穴

    イベントハンドラを設定するのに、以下のようにしてはいけません。

    window.onclick = MyOnClickMethod
    

    理由は以下のとおりです。

    1. 他のイベントを上書きしてしまいます。他者の作ったJavaScriptライブラリを使う場合など、特に注意が必要です。
    2. IEでは特定の状況下でメモリーリークを引き起こします。

    その代わりに、YUIなどを利用しましょう。

    YAHOO.util.Event.addListener(window, "click", MyOnClickMethod);
    

    [訳注:この件に関しては、404 Blog Not Found:javascript - Douglas Crockford on DOMも参考に]

  9. Focus Pocus [訳注:Hocus Pocusのもじり]

    DOMオブジェクトを生成してから、そこにfocusを当てたくなることはよくあります。

    var newInput = document.createElement("input");
    document.body.appendChild("newInput");
    newInput.focus();
    newInput.select();
    

    しかし、このやり方はIEではうまく行きません。IEでは、DOMオブジェクトを生成した時点では、オブジェクトは有効になっていないのです。解決法として、focusを遅延させるという手があります。

    var newInput = document.createElement("input");
    newInput.id = "TheNewInput";
    document.body.appendChild("newInput");
    setTimeout("document.getElementById('TheNewInput').focus(); 
    document.getElementById('TheNewInput').select();", 10);
    

    [訳者添削:あるいは]

    var newInput = document.createElement("input");
    newInput.id = "TheNewInput";
    document.body.appendChild("newInput");
    setTimeout(function(){
        document.getElementById('TheNewInput').focus(); 
        document.getElementById('TheNewInput').select();
    }, 10);
    

Dan the JavaScripter


この記事へのトラックバックURL

この記事へのトラックバック
「JavaScriptでありがちな9つのシマッタ」だそうです。 しまったと思うほどJavascriptは使ってないですが、 覚書として簡単に箇条書き及び詳しいサイトへのリンクを張らせていただきます。
JavaScriptでありがちな9つのシマッタ【地方の中規模印刷会社で苦悩するWebデザイナー改めWebディレクターの日記】at 2007年10月13日 12:06
怠翻 - JavaScriptでありがちな9つのシマッタよくありがちなシマッタがまとめられてます。おいらも IE の尻カンマエラーでどれだけの時間を使ったことか o...rz
JavaScriptでありがちな9つのシマッタ【Be an Idealistic Realist】at 2007年08月18日 19:01
原文はNine Javascript Gotchas 今回は弾さんによる訳を見ながらの感想。404 Blog Not Found:怠翻 - JavaScriptでありがちな9つのシマッタ 原文作者のPat Fitzsimmonsという人物は何者なのかよくわからぬ。ソフトウェア起業家
この作者はJavaScript使いなのか、という疑問【文系大学的IT系の悲哀】at 2007年08月17日 11:11
この記事へのコメント
著作権侵害ではないか、という話があるのですが・・・
http://anond.hatelabo.jp/20070818120923
訳者添削部分があることは気付いてないようですが。
Posted by 増田 at 2007年08月18日 12:38
2 は "MyObject = " のあとに new が抜けていますね。

3 はむしろ「グローバル変数も必ず var をつけて宣言しよう」としたほうがいいのでは。そうすれば IE でもエラーは起きませんし。
Posted by nanto_vi at 2007年08月17日 14:16
4の置換は初めて見ました。
いつもsplitしてjoinでやってました。
Posted by azt at 2007年08月17日 12:24
2について

alert(self.value); -> alert(self.alertMessage);

あと、オリジナルの問題ですが
「return self;」がないと、MyObjectがundefinedになりませんか?

もともとthisがWindowを見てしまっている少し「?」なコード(オリジナルが)のような気もしますが...

Posted by mattn at 2007年08月17日 12:18
Firefoxのスペルが違いますよ
http://www.mozilla-japan.org/support/firefox/faq#spell-abbreviate
Posted by vector at 2007年08月17日 10:14
(誤) MyObject.OnClick()を呼べば"Javascript rules"が表示される
(正) MyObject.ClickHandler()を呼べば"Javascript rules"が表示される

のような気がします。
Posted by LiosK at 2007年08月17日 09:58
微妙にインデントが乱れているのが気になります。
Posted by typo finder at 2007年08月17日 05:36