#java

ハマっちゃったException第二弾です。 実際はハマったワケではありませんが、 一応こんなExceptionがあると。

String blank = "";

int i = Integer.parseInt(blank);

これで余裕に下記のExceptionが出ます。

java.lang.NumberFormatException: For input string: ""

何も考えずにあるJavascriptの処理をJavaに書き換える作業で発生したんです。 JavascriptはブランクをparseIntするとNaN(Not a Number)になるが、 Javaは完全におちますね。。。

#jquery

表題の通り、IE6 + jQuery1.3.2の状態でbindする時に jQueryのnamespaceを使うと確実にメモリリークが発生します。 jQuery1.4.2では発生しないことを確認しました。

メモリリークが発生するコード

$("#foo").bind("change.abc", function(){});

上記”change.abc”のabcがnamespaceです。 それをなくすことでメモリリークは解消されます。 イベントハンドラの中身とは関係ありません。

メモリリークは発生しない

$("#foo").bind("change", function(){});

これはjQueryのbugとして上げられましたが、 完全に修正できなかったみたいです。 http://dev.jquery.com/ticket/4241で 当時の担当者のコメントを見ると

I had a really difficult time getting a reliable test case to verify this actually solves the memory leak. r6321 appears to have fixed this issue

「時間ないからちゃんとテストしてない、r6321の対応で解決できたように見える」と、 ずいぶん適当な回答ですよね。。。

#jquery

DOM操作を避けてjQueryのパフォーマンスを改善する掟です。 こんなコードがあるとしましょう。

パフォーマンスの悪い例

var list = *....*;    // 長さ100の配列とする

for (var i in list) {

    var li = document.createElement("li");

    $(li)
       .attr("id", "li" + i)
       .text(list*i*);

$("ul").append(li);

}

改善したコード

var list = *....*;    // 長さ100の配列とする

var li = "";
for (var i in list) {

    li += "<li id='li" + i "'>" + list*i* + "</li>";

}

$("ul").html(li);

まとめ

  • document.createElementの代わりにHTMLの文字列を作る
  • jQueryオブジェクトに属性やテキストを設定するのではなく、直接HTML文字列に書く
  • for文内毎回appendの代わりにhtml()を使う

実際のプロジェクトでやってみたら10倍以上は速くなりました。 とは言ってもこれはIE6でのパフォーマンスで、 FirefoxやIE8だと悪い例のコードても遅いとは実感できないくらいでした。

ちなみに $(li).attr(…).val(…).text(…)の方は読みやすいので結構気に入ったんですけど。。。

#jquery

jQuery 1.4.2ではこれは治ったようです。 jQuery最新版をお使いの方は下記のようなバグはもう発生しません。

サンプル

※jQuery 1.3.2で発生する問題※

HTML

<select>
	<option id="foo">&nbsp;</option>
	<option>11</option>
	<option>22</option>
</select>

<tr id="bar">&nbsp;</tr>

Javascript

var optionText = $("#foo").text();

// firefoxは0、IEは1
alert("select optionタグの をtrimした後のlength: " + $.trim(optionText).length);

var trText = $("#bar").text();

// firefoxは0、IEも0!
alert("trタグの をtrimした後のlength: " + $.trim(trText).length);

結果

selectのoptionタグのテキストにある“&nbsp;”に $.trimをかけて見ると Firefoxはちゃんとtrimしてlengthが0になったが、 IEはtrimできずlengthが1のままです。

しかしtrタグのテキストにある”&nbsp;”をtrimすると IEも正しくtrimしてlengthが0になるんです。。。

DEMO

jQuery最新版(1.4.2)を使うDEMO

#javascript

今まで全然気付かなかったんです、 JavascriptのArrayにはdeleteみたいなAPIがないことに。 配列の要素をindex指定で削除したい場合は代わりにsplice関数を使います。

splice関数

とほほからのレファレンスでは

array.splice(start, n, e1, e2, …) (N4) 0 から数えて、start 番目から n 個の要素を削除し、その代わりに e1, e2, …を値とする要素を埋め込みます。戻り値は JavaScript のバージョンによって異なります。

var xx = new Array("A", "B", "C", "D", "E", "F", "G");
xx.splice(2, 3, "c", "d", "e");   // "C", "D", "E" が小文字になります

indexで配列の要素を削除するには

myArray.splice(index, 1);

indexは削除する要素のindex、1はこの一つだけを削除する意味で 他のパラメータはいらないです。 またsplice後は配列そのものが変更されます。