gorogoronyan FC2

JavaScript: テストプログラムの実行とソース表示

概略

JavaScript: HTML 要素にテキストを出力する に関連して。

ローカルでちょっと試す HTML ではなくて、 Web にサンプルコードを表示し実行するときの話です。 うちのページでもサンプルコードを表示して実行する HTML がたくさんありますが、 このような HTML を作成するときの参考になりそうな話です。 document.write() をなるべく使わない方が良いという話も書いてしまったので document.write() を使わない方法でいろいろ。
JavaScript: document.write()

まとめ

実行結果を pre タグに出力する

document.write() を使わずに Element.append() で HTML にテキストを出力します。

実行結果の文字列を整形する

出力文字の列が揃うように String.padStart(), String.padEnd() などで調整します。
JavaScript: 文字列の処理 (1)

テストコードを eval() 関数で実行する (2023/12)

1行程度のコードと結果を出力する場合は eval() 関数を使うと便利です。
JavaScript: eval 関数

下のサンプルコードでは value.toFixed() が 2回現れています。 1個目はコード表示用の単なる文字列で、2個目の ${ } の中は実際に処理されるプログラムコードです。

writeln(`value.toFixed()      ${ value.toFixed() }     引数省略は 0 と同じ`);

同じ文字列を 2回書くと修正ミスなどで 表示するコードと実際に実行するコードが異なるといったトラブルが起こりやすいので、 両者を共通にして 1つの文字列だけで済むようにします。

let s = "value.toFixed()"
writeln(`${s}      ${ eval(s) }     引数省略は 0 と同じ`);

上のサンプルを簡素化する (2023/12)

上の TestJS_codetest_eval01.html では test() を外部の function にしているので引数 value も必要になります。 value がないと変数のスコープの外側になるので value が見つからないエラーが出ます。

//TestJS_codetest_eval01.html では test() に引数 value が必要なのが難点。
function test(code, comment = "", value = null){
	...
}

//テスト本体
{
	const value = 123.15;
	// value も引数で渡すことが必要。
	test("value.toFixed()",     "引数省略は 0 と同じ", value);
	...
}

毎回、引数 value を書くのも面倒なのでもう少し簡素化してみます。 test() をアロー関数で本体の処理の変数にします。 このようにすると value は同じスコープ内の変数になり test() 内でも見えている変数になるので、test() で引数 value を渡す必要がなくなります。

//テスト本体
{
	//test() をアロー関数の変数にする。引数 value は不要になります。
	const test = (code, comment = "") => {
		try {
			writeResult(`${ code }`, `${ eval(code) }`, comment);
		}
		catch(e){
			writeResult(code, "(error)",  `${comment} ${e}`);
		}
	};

	const value = 123.15;
	test("value.toFixed()",     "引数省略は 0 と同じ"); //引数 value は不要になります。
	...

セキュリティに注意

eval() 関数はセキュリティトラブルの話が出てくるので 固定の文字列ではない文字列 (ユーザーが入力した任意のコードなど) を処理するときには注意が必要です。

pre 要素内に script 要素を置く

pre 要素内に script 要素を置くと pre に id を持たせる必要がなくなります。 1つの HTML ファイル内に複数のサンプルを並べるときに便利です。

現在実行中のスクリプトがある script 要素は document.currentScript で取り出せます。 parentNode で親のノードをたどると script タグの外側にある親要素 (ここでは pre) も取り出せます。

//script タグの親要素の pre に append() で文字列を出力する。
function writeln(s){
	document.currentScript.parentNode.append(s + "\n");
}

//上の処理を分かりやすくすると?
function writeln(s){
	//現在実行中の script 要素を取得する。
	const script = document.currentScript;
	//script 要素の親の pre 要素を取得する。
	const pre = script.parentNode;
	// pre に文字列 s を出力する。
	pre.append(s + "\n");
}

// (参考) querySelector() では id 名が分からないと親の pre を
// 取り出せないので pre に id 名を付ける必要があります。
function writeln(s){
	document.querySelector( id名 ).append(s + "\n");
}

テストでエラーが発生しない場合は try catch も不要です。 下は正規表現のテストプログラムの例です。

サンプルのソースコードを表示する

ソースコードも HTML に表示します。こちらも Web 表示用のコードと実際に実行するコードを別々に用意すると面倒なので、 実行するコードをそのままテキスト化して表示します。

ソースコードの表示は HTML 読み込み完了後 (onload イベント) のタイミングでコードテキストを取り出してソース表示用の要素にセットします。
JavaScript: プログラムを実行するタイミング

HTML 読み込み完了後に実行するサンプルの場合

先に HTML の読み込みの途中では何も行わず、 読み込みを完了した後でボタンを押して何か処理を行うサンプルの例です。

HTML を読み込む途中で実行するサンプルの場合

HTML を読み込む途中ですぐに実行するプログラムでは 実行結果の文字列も HTML の中に出力されるので、 ソースコードの表示のときに実行結果を除去したテキストにすることが必要です。

上の TestJS_codetest_currentScript01.html などのように pre タグ内に script タグを置いて pre.append() で文字列を出力するプログラムでは </script> の後に append() で出力した文字列が追加されます。

<pre>
<script>
writeln("サンプルテキスト");

function writeln(s){
	document.currentScript.parentNode.append(s + "\n");
}
</script>
<!--ここに writeln() の文字列が出力される-->
</pre>

単純なサンプルならコードテキストの </script> と </pre> の間のテキストを削除すれば間に合います。

// /script タグと /pre タグの間のテキストを除去する例。
text = text.replace(/<\/script>[\s\S]*?<\/pre>/g, "</" + "script>\n</pre>");

ただし、 script タグや pre タグを複数含むコードになるとまずいです。 下の例のようなコードの場合 </script> から </pre> までの間のテキストを削除すると必要なテキストまで削除されます。

◎ </script> と </pre> の間のテキストを単純に削除するとまずい例

・script タグが複数あるサンプル

<pre>
<script src="sample.js"></script>
<!--削除されるテキスト-->
<script>
writeln("サンプル");
</script>
</pre>

対策例として実行結果が出力される箇所に目印になる文字列 ( 例えば、<!--result--> ) を入れておいて、 直前に現れる </script> タグから <!--result--> までの間のテキストを削除します。

◎ 実行結果のテキストを削除

<pre>
<script src="sample.js"></script>
<script>
writeln("サンプル");
</script>
ここに実行結果が出力される。このテキストを削除する。
<!--result-->
</pre>

1つの HTML ファイルにサンプルを複数並べる場合は <div id="SAMPLE"> の id が 1個だけだとまずいので id にも通し番号を付けるなどの工夫をします。

行番号を表示する

TestCSS_flex_pre_source_code01.html
pre タグで HTML のソースコードを表示するサンプル。 こちらは見た目のイメージです。 行番号とソースコードの pre タグを左右に並べます。
CSS: flex

関連

inserted by FC2 system