スポンサーリンク

JavaScriptの動かないコード (初級編) 配列とオブジェクトの宣言エラー


以下のJavaScriptコードが意図した動作をしないのは,なぜですか。(制限時間1分)

<input type="button" value="クリックして表示" onClick="f()">

<script language="JavaScript">

function f()
{
	// 配列
	var a = new Array(
		"H","e","l",
		"l","o",",",
		"w","o","r",
		"l","d","!",
	);

	// Hello,world! と表示
	alert( a.join("") );


	// オブジェクト
	var b = {
		w : function(){alert("w");},
		x : function(){alert("x");},
		y : function(){alert("y");},
		z : function(){alert("z");},
	};

	// x と表示
	b.x();
}

</script>




答え



宣言方法のエラーが2か所ある。

一つ目のエラー

まずIEFF共に,配列宣言の最後でひっかかり,読み込み時エラーになる。

		"l","d","!",
	);

末尾のコンマが余分だ。1行目をコピー&ペーストして2行目以降を作成した場合,見落としやすい。

Firefoxでは,この1つ目のコンマさえ取り除けば,冒頭のコードは正常に動く。


この箇所でのIEのエラーメッセージは,「ランタイムエラーが発生しました。構文エラーです。」というもの。

カンマを取り除けば,IEも,これと同じ箇所でのエラーは出なくなる。


二つ目のエラー

しかし,IEには2つ目の問題がある。

		z : function(){alert("z");},
	};

IE(そしてOperaも)では,オブジェクトの最後のプロパティの末尾にコンマを付けてはいけない。
これは読み込み時エラーになる。

json形式のデータならば全ての場合にあてはまり,Ajax用のライブラリ利用時などに頻繁に発生する。IE限定のよくはまる問題。


表示されるエラーメッセージは,「ランタイムエラーが発生しました。識別子,文字列または数がありません。」というもの。


類似の問題

上の2つは,どちらも変数の宣言の時点でエラーが出るというものだった。


しかし更に厄介なことに,類似のエラーで,「宣言時にはエラーが出ず,実行時に IE だけエラーになる」というものがある。


下記のコードを動かしてみよう。

<input type="button" value="クリックして表示" onClick="f()">

<script language="JavaScript">

function f()
{
	// JSONを要素に持つ配列
	var arr = [
		{ value : 1 },
		{ value : 2 },
		{ value : 3 },
	];
	alert( "配列の長さは" + arr.length );
	
	for( var i = 0; i < arr.length; i ++ )
	{
		// i 番目のオブジェクトを取り出し
		var obj = arr[i];
		
		// そのオブジェクトの保持するデータを表示
		alert( obj.value );
	}

}

</script>

配列宣言部の末尾のカンマに注目。


FFでは,「配列の長さは3」「1,2,3」と表示される。

これが所望の動作だ。


ところがIEでは,なんと「配列の長さは4」「1,2,3」と表示された後で,

"value"は Null またはオブジェクトではありません。

というエラーになる。


配列宣言時に末尾にカンマを付けてしまったため,IEではそのカンマの後に,配列中で「空の要素」が一つ余計に付け加えられてしまっているのだ。

そして,空の要素の value という属性を参照しようとしても無効になる。


new Array() の宣言で末尾カンマが存在したときには IE・FF 共に宣言時エラーになってくれたが,[ 要素, 要素, … ] の宣言では,実行時になって初めて不具合に気が付くという事になる。


対処法を考える

問題が発生する原因は,配列の場合もオブジェクトの場合も,いずれも

  • 行をコピペしたため
  • 末尾要素を削除した際,その直前のコンマを消し忘れた
  • CGIで動的にJavaScriptコードを生成した際,末尾を特別扱いしなかった

という理由が挙げられるだろう。


対処法として「コンマを行(次要素)の最初に書くのはどうか?」という人もいる。

do u have extra comma? ok, ie will destroy your application!
http://extjs.com/forum/showthread.php...

しかし,行の最初にコンマを書いた場合には1行目が特殊になるわけで,結局どこかの行を特別な注意対象にしておかなければならない。
記法での解決は難しそうだ。


この「末尾コンマ問題」を起こしていないかどうか,コーディング時やエラー発生時に,意識して疑ってみるしかないだろう。


あるいは,もし可能なら,配列にデータを挿入する際には初期化であっても必ず push() などの専用関数を使うという方針を固守するという手もある。