JavaScript
HTML5

エラーの原因はJavaScriptのコメントの文字化けかコメントの場所か

次で作成したJSの一部が動作しなくなっていたことに気づいた。
目次自動作成付Webページテンプレート
このJSを他のファイルで使おうとしたときに意図された動作がないことで気づいた。

Webコンソールに次のエラーが出ていた:

  • Uncaught SyntaxError: Invalid or unexpected tokens formatting_with_toc.js:105 以下省略

JSをエディタで見ている分には警告もエラーも出ていないが,唯一気になったのは,メモのように後で付け足したコメントである。このファイルはいちいちコメントを入れた。

ブラウザのインスペクタでは上記のエラーのファイル名及び行の部分をクリックするとブラウザのインスペクタ内でJSファイルが展開され,該当箇所にフォーカスされる。すると,次のように(コメントが)文字化けしていた:

if((hds_len==1)&&(art_len>0)){ /* begin : if */
    setArea_TOC(); // TOCのエリアを作成
    setID_and_Class_Basic();// 主要なIdやClassを設定
    set_SingleContainer(); // divコンテンナを設置し内部コンテンツをコンテナへ移動
    { // TOC部分のコンテンツを作成
      tocH2(); 

上はFirefoxで見たものだが,文字化けの仕方はChromeで見た方がよく見る文字になる。要するにこれは全角(日本語)が直接原因である。基本的にはコメントは拙い英文にしているが,たしか面倒になって後で日本語でコメントを足したものをアップロードし直していた。

  • 追記 指摘していただき気づいたが,上のコードの文字化け部分には文字化け以前にコメント外に全角空白が残ってしまっているものが含まれている(スラッシュがない行で文字化けしている部分及びスラッシュより前で文字化けしている部分)  

JSファイルとHTMLファイルの文字コードが不一致である場合の問題があるらしいが,問題はコメント自体がエラーの原因になる可能性があるという点だ。コメントアウトしているのだからコードとしては関係がないという理解に立てば,それが挙動に影響を与える可能性を予測する必要性はないはずだが,実際には「コメントの文字化けさえ」エラーの原因となる。もっとも,試していないからわからないが,文字化けだけでなく,その文字化けしたコメントとコードの位置関係との両方によって,その文字化けコメントがエラー原因になってしまうということなのかもしれない(たとえば,上の例の文字化けコメントを,各コードとは別の行に改行して配置していたなら,とりたててエラーとはならなかったのかもしれない [1]。いずれにせよ,自らのコメントがIDEの関知しないところでわざわざカスタムのエラーオブジェクトとなって散在するオブジェクト指向ボランティアになる可能性があることには違いがない。

コメントについては,コメント自体がエラーになる可能性も視野に入れる必要がある。コメントの運用方針の良し悪し論は格別,一般論として,コメントが次のようにエラーの原因となることがある点に注意が必要である:

  1. 関数の引数括弧内のコメントが改行されている,といったケース(コメントがコードを壊してしまう場合)
  2. コメント自体が文字化けしている場合(今回のケース:ただし,[1]を考慮すると,同時に1の場合にも該当することになる:言い換えれば,文字化け自体はエラー原因の一部ということになる)

そうすると,以下の二点に注意すれば良いだろう:

  • コメントがエラー原因になる可能性がある
    • cf.日本語,文字コード
  • コメントとコードの位置関係が妥当かどうか

もっともシンプルな予防法は,やはりはじめから英文にしておくしかなさそうだ。また,実際にはコメントを,少なくとも直接には長々と書かない方が良いことは言うまでもないから短い英文コメントにするというのも手だ。または全角自コメント賠責保険に入るか。

  • 追記 念の為,ユーザー設定「ファイル>基本設定>設定」から次を設定することで,保存(Windows: Ctrl+Sなど)時に余分な空白を自動で削除してくれるオプションがVisual Studio Codeについている(他のエディタでも空行や行末空白を削除する機能が備わっているのが普通である):
"files.trimTrailingWhitespace": true

また,空白文字を表示させておくためには以下のオプションをnone以外にする

"editor.renderWhitespace": "boundary"