【javascript】文字列変数に改行をいれるとイカれる


javascriptの文字列変数にソースコード上でそれとわかるような形で改行いれるとページ全体がなんかおかしなことになる。
少なくとも、その変数使ってるjavascriptは動かなくなるようだ。
まあ普通に考えるとそういうもんだろう。
個人的な感覚でいうと、変数に固定の文字列埋め込むケースではコーディングミス(誤記、というか)以外に考えられらない。
だから普通発生しないはずである。
ただ実際に発生して困ったので備忘録として残す。


 


 


HTMLの具体的な実例で見てみると。

(1)固定値埋め込み:改行なし

 

  
<html>  
	<head>  
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
		<meta http-equiv="Content-Script-Type" content="text/javascript">  
	&lt;script type="text/javascript"&gt;  
	<span style="color: green;">&lt;!--  
		<span style="color: red; font-weight: bold;">var strVal = "あいうえお";</span>  
		  
		function alertOn() {  
			alert(strVal);  
		}  
	// --&gt;</span>  
	&lt;/script&gt;  

	&lt;title&gt;Test Js Alert(No Line)&lt;/title&gt;  

&lt;/head&gt;  
&lt;body&gt;  
	&lt;h1&gt;■改行なしの文字列を表示します。&lt;/h1&gt;&lt;br/&gt;  
	&lt;br/&gt;  
	&lt;input type="button" value="ここをクリックするとjs変数を表示します。" onClick="alertOn()"&gt;  
&lt;/body&gt;  

</html>



(2)固定値埋め込み:改行あり

 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
<html>  
	<head>  
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
		<meta http-equiv="Content-Script-Type" content="text/javascript">  
	&lt;script type="text/javascript"&gt;  
	<span style="color: green;">&lt;!--  
		<span style="color: red; font-weight: bold;">var strVal = "  

あいうえお";

		function alertOn() {  
			alert(strVal);  
		}  
	// --&gt;</span>  
	&lt;/script&gt;  

	&lt;title&gt;Test Js Alert(No Line)&lt;/title&gt;  

&lt;/head&gt;  
&lt;body&gt;  
	&lt;h1&gt;■改行ありの文字列を表示します。&lt;/h1&gt;&lt;br/&gt;  
	&lt;br/&gt;  
	&lt;input type="button" value="ここをクリックするとjs変数を表示します。" onClick="alertOn()"&gt;  
&lt;/body&gt;  

</html>



(3)自ページ内のテキストエリアから設定

 

  
<html>  
	<head>  
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
		<meta http-equiv="Content-Script-Type" content="text/javascript">  
	&lt;script type="text/javascript"&gt;  
	<span style="color: green;">&lt;!--  
		  
		function alertOn() {  
			var strVal = document.getElementById("TEXTAREA_FREE").value;  
			alert(strVal);  
		}  
	// --&gt;</span>  
	&lt;/script&gt;  

	&lt;title&gt;Test Js Alert(Free Input)&lt;/title&gt;  

&lt;/head&gt;  
&lt;body&gt;  
	&lt;h1&gt;■自由入力の値を表示します。&lt;/h1&gt;&lt;br/&gt;  
	&lt;br/&gt;  
	ここ↓に入力した値を表示します。&lt;br/&gt;  
	&lt;textarea width="300" height="200" id="TEXTAREA_FREE"&gt;&lt;/textarea&gt;  
	&lt;br/&gt;  
	&lt;input type="button" value="ここをクリックするとjs変数を表示します。" onClick="alertOn()"&gt;  
&lt;/body&gt;  

</html>




それぞれボタンをクリックすると変数値をalertで表示するだけのシンプルなHTMLである。
(1)は言わずもがな、全然問題ない。(普通に"あいうえお"が表示される)
(3)は表示する値をTEXTAREAから取得するため、TEXTAREAへの入力内容次第では当然改行が入ることもあるが、
仮に改行をいれて入力していても問題なくalertで表示できる。(改行もちゃんと表現された状態でalertされる、いわゆる"あいうえお\nかきくけこ"とかと同じ扱いになる)
ただし、(2)はボタンを押しても反応がない。
Internet Explorerの開発ツールによれば、ボタンクリック時に起動しているjavascriptの関数「alertOn()」が未定義で呼び出せない。
関数定義のブロックと変数に値を埋め込んでいる箇所はコード上で異なるが、
意図的に改行をいれてしまったことでjavascript全体がイカれてしまっている。

冒頭で言った”変数に固定の文字列埋め込むケースではコーディングミス(誤記、というか)以外に考えられらない。”というのは
上に挙げた例でいうところの(2)にあたるケースで、
要するにこういう書き方↓は普通は(=意図的には)しないよねという意味である


<script type="text/javascript">
<--
var STR_VAL = "あいうえお ←わざわざここで改行なんかしないだろjk…という意味
かきくけこ";
// -->
</script>





↑までの話ならただのコーディングミスで話が付くのだが、
実際に遭遇した時はjspで変数設定している箇所に原因があった。
簡単な実例として、
「HTMLのTEXTAREAに入力された値をPOSTして、JSPにFORWARDした後、受け取った値をjavascriptでalert表示させる」
ようなものを考える。

(4)入力元HTML

 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
<head>  
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
	<title>Test Textarea</title>  
&lt;meta HTTP-EQUIV='Cache-Control' CONTENT='no-cache'&gt;  
&lt;meta HTTP-EQUIV='Pragma' CONTENT='no-cache'&gt;  
&lt;meta HTTP-EQUIV='Expires' CONTENT='-1'&gt;  

</head>
<body>
<h1>■最初の画面です。</h1><br/>
<br/>
<form action="/linecodetest/TestServlet" method=“post”>
ここになんか入力↓<br/>
<textarea width=“300” height=“30” name=“textarea_test” id=“textarea_test”>
</textarea>
<br/>
<input type=“submit” value=“GO! Submit!!">
</form>
</body>


(5)間にいるServlet

 

import javax.servlet.*;  
import javax.servlet.http.*;  
import java.util.*;  
import java.io.*;  
import java.text.*;  
import java.net.*;  
import javax.mail.internet.*;  

public class TestServlet extends HttpServlet {

private static final DateFormat LOG_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");  
  
private static final String ENCODING_UTF8 = "UTF-8";  
  
private static final String STR_PARAM_TEXTAREA_TEST = "textarea_test";  
private static final String STR_URL = "/jsp/forward.jsp";  
  
public void doGet(HttpServletRequest req , HttpServletResponse res) throws ServletException,IOException {  
	this.doProcess(req,res);  
}  
  
public void doPost(HttpServletRequest req , HttpServletResponse res) throws ServletException,IOException {  
	this.doProcess(req,res);  
}  

private void doProcess(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException {  
try {  
	String strVal = request.getParameter(STR_PARAM_TEXTAREA_TEST);  
	  
	if (strVal == null) {  
		throw new ServletException(STR_PARAM_TEXTAREA_TEST + " is null");  
	}  

	printLog("**** Debug Print -START- ****");  
	printLog(STR_PARAM_TEXTAREA_TEST + " = " + strVal);  
	printLog("**** Debug Print -E N D- ****");  
	  
	HttpSession hs = request.getSession();  
	  
	hs.setAttribute(STR_PARAM_TEXTAREA_TEST,strVal);  
	RequestDispatcher rd = request.getRequestDispatcher(STR_URL);  
	rd.forward(request,response);  
	} catch(ServletException e) {  
		throw e;  
	}  

}

private static void printLog(Object msg) {  
	StringBuilder sb = new StringBuilder();  
	sb.append(LOG_FORMAT.format(new Date()));  
	sb.append(" ");  
	if (msg != null) {  
		sb.append(msg.toString());  
	}  
	  
	System.out.println(sb.toString());  
}  

}


(6)forward先JSP

 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
<head>  
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
	<title>Test forward</title>  
&lt;meta HTTP-EQUIV='Cache-Control' CONTENT='no-cache'&gt;  
&lt;meta HTTP-EQUIV='Pragma' CONTENT='no-cache'&gt;  
&lt;meta HTTP-EQUIV='Expires' CONTENT='-1'&gt;  
  
&lt;script type="text/javascript"&gt;  
&lt;!--  
	var REQ_VAL = '&lt;%= session.getAttribute("textarea_test") %&gt;';  
	function alertOn() {  
		alert("前画面からもらった値は\n" + REQ_VAL);  
	}  
	  
// --&gt;  
&lt;/script&gt;  

</head>
<body>
<h1>■forward先画面です。</h1><br/>
<br/>
<input type=“button” value=“ここを押すと前画面でもらった値を表示します。” onClick=“alertOn();">
</body>



(6)はボタンクリックでjavascriptの変数「REQ_VAL」をalertに表示させるが、
この値はHttpSession#getAttributeで受け取った後にHTMLのソースコードとして展開されるため、
HttpSession#getAttributeの値次第ではここで改行が起き、変数の設定箇所が2行に渡るコードになり、(2)と同じ状態になる。
結果的にjavascriptが動作しない…という現象が起きる。

ことこのケースでいえば、
HttpSession#getAttributeで取得できる値を”入力する(設定する)側”は(4)で、それを表示するのが(6)という構成なので、
つまり自分で入力して自分でコードをブッ壊しているという間抜けな状況だが
この項目の取得元が「外部システムに依存していてデータの仕様がよくわからない」というようなケースでは結構こういうことも起き得るだろう。
(そもそもデータの仕様を確認せぬまま実装してはいけないけど…)
まあこういう危険性をはらんでる時点で、改行含むかどうかに関わらずこういうコーディングをしてはいけないのだろう。