JavaScriptのトラブルシューティングメモ

ここに書いてある原因と解決策はあくまで私がやったミスとその解決策であり、 その現象に対する原因がすべて書いてあるというわけではありませんのでご注意下さい!

SUBMITボタンにonSubmitを書いたのに、その関数が呼ばれない
ぎゃはは。onSubmitが書けるのはSUBMITタグではなく、FORMタグです。

onClickで関数をコールすると、
「オブジェクトでサポートされていないプロパティまたはメソッドです」
関数名と同名のフォーム要素がある。

MSIEで"08"をparseIntすると8ではなく0になってしまう。
parseIntの2番目の引数で基数を指定してないためです。 省略すると、MSIEでは0で始まる文字列は8進数として解釈されるためです。 10進数を強制したければ、次のようにします。

month = parseInt(adate.substr(4,2), 10);

なおOperaでは0で始まる文字列も10進数として解釈されるようです。

"12zz"のような文字列をparseIntしてもNaNにならず、12と認識される
parseIntの仕様です。先頭から数字がある限り読み取り、それを整数に変換します。
数字でない文字に出会ったらそこで読み取りは終わりますが、エラーになるわけではありません。
またNaNになる、つまりisNaN関数に渡すと真になるのは、先頭文字が数字でないときだけです。

DateのgetYearメソッドが返す値が古代…
getYearの返す値はブラウザによって仕様が異なります。 MSIE 6.0では西暦で返しますが、Opera7では西暦から1900を引いた値を返します。 必ず西暦で得たい場合には、代わりにgetFullYearメソッドを使います。 こちらはECMA Scriptで仕様化され、常に4桁の西暦で年が返されます。

ループの中で別の関数をコールしていると、CPU使用率が100%になり、IEでは"Stack Overflow at line *"というダイアログが出る
無限ループしているのが原因です。 私がはまって延々悩んだ例が、ループ変数をvarをつけて宣言しないでグローバル変数として使ってしまい、 関数同士で衝突していた、という例です。
より具体的にいうと、関数Aでvarをつけずに変数iをループ変数として0から9までループし、 その中で関数Bを呼んでいるとします。 関数Bの中でも同様にグローバルな変数iをループ変数として0から2までループするようになっていると、 関数Bを呼ぶ度に変数iの値は2に戻ってしまうので、 関数Aのループが終了せず、スタックオーバーフローになる、ということです。 この現象はMSIE 6.0とOpera7で見ることができました。

JavaScriptのラジオボタンのよくある間違い
ラジオボタン"opkbn"のどれかを選択状態にしようとして、

document.forms[0].opkbn.value = "1"

としてうまくいかないので延々悩みます。正解は

if(! document.forms[0].opkbn[0].checked &&
   ! document.forms[0].opkbn[1].checked){
  document.forms[0].opkbn[0].checked = true;
}

このように、ボタン個々のオブジェクトのcheckedプロパティを直接操作します。

「オブジェクトを指定して下さい」
これはMSIE 6.0以降で、「関数が見つからない」という意味の専門用語です。 JavaScript関数の名前のスペルミスなどを確認します。

文字列の長さはlength()メソッドでは得られない?
str.length()ではなく、str.lengthです。括弧はいりません。

文字列"-1"を格納した変数aに「0 + a < 0」を適用すると偽になってしまう。数値に変換するには?
頭に「0+」をつければ文字列を数値に変換できるというのは大きな勘違い。 というか、それはJSPのEL(Expression Language)の常識と混ざっちゃってますね。
JavaScriptでは、文字列と何かを演算したら、 順序に関係なく文字列でない側を文字列に変換して演算します。
上記の状況では、単に「a < 0」で右辺が数値なので数値として比較してくれます。

「";"がありません」というエラーになるが、全ての文末に;をつけている。
もしやelse ifをelseifと書いておりはせぬか?
仲間のスクリプト言語PHPがelse ifもelseifも両方使えるので(動作も同じ)、 うかーりしているとJavaScriptでも書いてしまうかもしれないですね。

Operaの場合だけ時々「document.aaaForm.submit()」が効かず、同じページが再ロードされてしまう。
これは

<a href="#" onClick="document.aaaForm.submit()">ここをクリック</a>

このように隠しフォーム(aaaForm)をJavaScriptでSubmitさせているページで、 普通はOpera、MSIE、FireFoxのいずれでも期待通りにSubmitされるのですが、 時折何かの拍子にOperaの場合だけ動作しなくなり、 同じページが再表示されるようになってしまう (一度その現象が起きると、以後そのURLの文書は必ずそのようになってしまう) というものです。 これはOperaだけではなくて他のブラウザで見る場合も同じなのですが、本来的に正しいのは

<a href="#" onClick="document.aaaForm.submit();return false">ここをクリック</a>

こうです。 Submitを実行した後、 return falseでa要素のonClickイベントを明示的に中断するのが正しい書き方です。

0.17と0.53の和が0.7にならないよ?
実際にやってみましょう。

var a = 0.17;
var b = 0.53;
var c = a + b;
document.write("result=" + c);

確かに、「0.7」ではなく「0.7000000000000001」となります。 これはJavaScriptの循環小数の演算誤差と呼ばれるもので、 二進数で綺麗に表現できない小数を含む加算、乗算で発生します。
こんなこともあろうかと(ウソです)、JavaScript 1.5(Windows版IEでいうと5.5)以降では、 「Number#toFixed()」という関数がサポートされました。上の例でいくと

c = c.toFixed(2);
document.write("result=" + c);

とすると、小数点以下2桁で丸めてくれます。この例では引数が「2」なので2桁になるのです。
このとき、小数点以下3桁目は「四捨五入」になるのが仕様のようなので、 仮に「0.69999…995」のような値であったとしても、 「小数点以下2桁ならば」どんなWebブラウザでも予想通りの処理をしてくれます。

でも0.7をtoFixed(0)しても1にならないよ?
何事にも例外があるというではないですか(帰れ)
MSIEでは、0.5以上1.0未満の値に対して引数に0を指定すると、 1ではなく0が返ってしまいます。これでは四捨五入とはいえませんね。 でもそういう動作なんだから仕方ないですね。 (MSIE7でも。なおOpera9は上記の場合に正しく1を返します) もういや!こんな生活!!
ではどんな場合でも必ず四捨五入をさせるにはどうすればよいのか? JavaScriptには、整数に丸めるMath.round()関数しかなく、 小数点以下指定桁で四捨五入する関数がないので、 答えは 「小数点以下n桁で四捨五入したい場合、値に10のn乗をかけてMath.round()した後、 また同じ数で割る」という素晴らしく分かりやすい方法に頼ることになります。

変数名に"top"を使ったときだけ計算がおかしい(Opera)
以下の例でやってみましょう…

<script type="text/javascript"> 
var top = 10;
</script>
<form>
<input type="button" value="表示" onClick="alert('value is ' + (top*5))"/>
</form>

このボタンを押すと、MSIE8、Chrome5などでは「50」と結果が表示されますが、 Opera10だと「NaN」と表示されると思います。
原因は、HTMLのscriptタグ内では、windowオブジェクトのプロパティは省略可能ですが、 "top"もwindowのプロパティの1つだからです。 Operaでは、onclickハンドラの中のtopを参照したとき、 グローバル変数よりも、window.topを優先して参照してしまうのでこうなるようです。
解決方法は?ってそれは簡単、変数名をtop以外にすればいいだけです。


Ajaxっぽいことをしている際のトラブルシューティングメモ

responseTextで応答を受け取る際に、MSIEだと「システム エラー 1072896658」が発生する
Webサーバからの応答のContent-Typeのcharsetが、 MSIEの知らない文字セットになっていると発生します。典型的には「Windows-31J」です。 Content-Typeを「text/html;charset=Windows-31J」ではなく、 「text/html;charset=Shift_JIS」にすると直ります。

MSIE、OperaでresponseTextやresponseXMLで応答を受け取ると、全角文字が????となる
UTF-8、Shift_JIS、EUC_JPならば、基本的にMSIEやOperaでは特に細工をしなくても????にはならないはずです。 XMLHttpRequest.getAllResponseHeaders()を使ってみて、 Content-Typeヘッダが、本当にサーバ側のプログラムで意図したcharsetになっているかを確認します。
かく言う私が最初にはまったのは、 サーバ側のプログラムをJava言語で、つまりServletで使っていたわけですが、 HttpServletResponse.setContentType()で応答ヘッダのContent-Typeでcharsetを指定するのですが、 setContentType()は、getWriter()より先に呼ばないといけないという点です。 これを順番を逆にしていたため、設定したはずのContent-Typeになっていない、 と延々悩むはめになってしまいました。

Operaでは問題ないのに、MSIEだとresponseXML.getElementsByTagName()で内容が全く取得できない
これまたわかりにくい注意点ですが、MSIEでは、 応答のContent-Typeが「text/xml」でないと、 responseXMLでXMLDocumentオブジェクトが取得できません。 text/plainやtext/htmlになっていないか確認して、すぐにtext/xmlに直しませう。

Misc. Topics Top

(first uploaded 2005/04/15 last updated 2010/08/01, URANO398)

テレワークならECナビ Yahoo 楽天 LINEがデータ消費ゼロで月額500円〜!
無料ホームページ 無料のクレジットカード 海外格安航空券 海外旅行保険が無料! 海外ホテル