プロが教えるわが家の防犯対策術!

htmlであるボタンを押すと、そこで実行するはずの関数が未定義になる、
という不具合が出ていたのですが、
JavaScript(<script>)の記述場所を変更する事により、対処することができました。

でもまだ、理解ができずにいます。

たとえば

<head>
<script ・・・・外部jsファイル>
</head>
<body>
<input type="text" name="hizuke" ・・・>
<input type="button" name="newdisp" value="表示" onclick="hyouji();">
 ・
 ・
<input type="hidden" name="syori" value="">
 ・
 ・
 ・
</body>
 ・
 ・
※外部jsファイルでhyouji()関数記述


のようなhtmlで、今回「表示」ボタンをクリックするとエラーになり、
エラーの詳細を見ると 
  hyouji()が未定義です
となり、
JavaScriptの関数がまだ読み込まれていないから
記述を後に移動したほうがいいというアドバイスを受け、
このhtmlを

<head>
</head>
<body>
<input type="text" name="HIZUKE" ・・・>
<input type="button" name="newdisp" value="表示" onclick="hyouji();">
 ・
 ・
 ・
<input type="hidden" name="syori" value="">
 ・
<script ・・・・外部jsファイル>
</body>
 ・
 ・

のように変更して、エラーをなくすことができました。

外部jsファイルのhyouji()関数の処理は
「syori」のhiddenに「hyouji」というような処理識別をセットし、
submitしています。

hyouji()関数の前にもたくさんの関数が定義されていて
その中には
   var aaa = document.form1.xxxx.value;
などの記述もたくさんあります。

<script>の記述場所を移動したことで
   htmlを読み込んで、
   「表示」ボタンを表示し、
   jsファイルを読み込む・・・
という処理順序になると思うのですが
表示ボタンをクリックしたときには、
jsファイルの読込みは終了しているのでしょうか???

ボタンをクリックした時にはjsの読込みを終了していないといけないと
思うのですが、なぜjsの記述を<inputボタン>の記述より後のほうに移動させて、
未定義関数が解決されるのかがわかりません。


エラーの内容が
  オブジェクトが見つかりません
などだと、hidden項目が後に記述されているからか・・・と理解できるのですが。



うまく伝わるか不安ですが、
ボタンクリックの前にはJavaScriptの関数が読込みが
終了していなければならないのはわかるのですが、
なぜ、ボタンの表示より、後に記述することで解決できるのか
解説していただけると助かります。

よろしくお願いします。

A 回答 (4件)

原始的なプリントデバッグになりますが、外部スクリプトの位置を最初に戻し、スクリプト末尾に



alert(typeof 関数名);

を追加して下さい。関数が定義されていれば中身が表示されますし、未定義なら undeinfed が表示されます。また、アラートが出ない場合はスクリプトが読み込まれていないか、途中でエラーを出しています(IE は静かに死ぬことがあります)。スクリプトが読み込まれているかを確認するには、alert() をスクリプト冒頭に移動してアラートが出れば良い。

IE が静かに死ぬケースにはいくつかパターンがあったはずですが、今思い出せません(すみません)。可能性のひとつはスクリプトファイルの文字化けです。

また、キャッシュが悪さをすることもあります。不可解なバグに悩まされたときは、ブラウザを再起動すると何事もなく動くことがあります。

ただまあ、Firefox で未定義であったということは、読み込まれていなかった可能性が高いと思うのです。

この回答への補足

お礼の補足になりますが。。。


IEは静かに死んでしまった感じでしょうか。
スクリプトフアイルの文字化け・・・もあるんですね。。。
ブラウザを再起動させてもしばらくはダメのようでした。
時間を置けばまだしばらくちゃんと動いてくれ、しばらくするとまたダメ・・・になる。

この原因を調べろ って言われてますが
どんな原因でこうなるのか、 未だわかりませんし、
解決方法も正しいのか判断できません。

そういえば、前にもキャッシュの問題で苦労しました。
消したはずの外部jsファイルなのに、その中の関数がいつまで経っても動いてしまうんです。
キャッシュを何回もクリアしても、その関数は生きてました。

そのとき、IEをアンインストール、インストールしてもらってもダメだったので
確かIEのバージョンを変えてもらって対処できたような記憶があります。

ちょっと話がそれてしまいましたが、
スクリプトファイルの文字ばけのあたりについても調べてみたいと思います。
文字化けしない方法って<META・・>以外に特別に何かあるでしょうか?

補足日時:2012/04/09 11:19
    • good
    • 2
この回答へのお礼

ありがとうございます。

現象が出ているときに、alert・・・は入れて確認しました。
結果は、
alertが出るときは、当たり前に情報の表示がされます。
同じマシン、同じ環境で何度か「表示」ボタンを押すと、
そのうち(15分くらい経過後)、alertが出なくなり、
iframe内は空白のままで、ステータスにエラーがでます。

不可思議な動きでした。。。
今は<script>を下部に移動して、なぜか?!うまく動いています。

この方法を次の案件にも対応させるかどうか、決めなければならないときになりそうです。
どうしたらいいでしょう!!!

お礼日時:2012/04/09 11:08

No.2 補足より:



> 特に今回の事象の解決策はこれでした。
> ・onMousemove、onClickで指定された関数は、HTMLのロードが完了した後に定義しなければならない。

いいえ、そんなことはありません。

> <HEAD>内記述の外部Scriptファイルが読み込みが終わっていないのに、<BODY>の表示が開始され

であれば、HTML 4.0(1) および HTML(5) の規定に違反しています。現状、私はそのようなブラウザの存在を聞いたことがありません。

---
今のところ、ふたつの可能性があります。

・単純に、外部スクリプトの URI ミスであった。script を移動したときに @src を書き直し、たまたま直った。

・『HTMLのロードが完全に終わっていない状態でgetElementByIdなどを呼び出す』箇所があり、そこでエラーを出して止まっていた。そのため、それより後ろで定義されている関数(この場合は関数式)が未定義のままになった。

とにかく、仰る現象と解決方法は、理屈にも(拙いながら)私の経験にも合いません。と言うより、もし仰ることが本当なら、繰り返しますが HTML(5) の規定に適合しませんので、ちょっと大きな問題になります。

script には @defer がなかったんですよね?

この回答への補足

> 単純に、外部スクリプトの URI ミスであった。
> script を移動したときに @src を書き直し、たまたま直った。

これはないです。

> 『HTMLのロードが完全に終わっていない状態で
> getElementByIdなどを呼び出す』箇所があり、
> そこでエラーを出して止まっていた。
> そのため、それより後ろで定義されている関数(この場合は関数式)が
> 未定義のままになった。

getElementByIdはたくさん使っていますが、全てjs外部ファイルの関数内の処理になっています。
CGIアプリで吐き出すhtmlの<SCRIPT>内に直接記述はありません。


> script には @defer がなかったんですよね?

バージョンはHTML 4.01 になります。


cgiアプリの処理の流れは、
 js外部ファイル読込み→上部から画面表示→「表示」ボタン表示→
 「iframe」(枠だけ)表示→onLoad処理でiframe内に最新情報表示
です。
(iframe・・・、何か影響ありますか?)


現象としましては
いつまで経ってもiframe内に情報が表示されないので、
「表示」ボタンを押したらエラーになった。
IEでは
  オブジェクトを指定してください ライン1 文字1
のエラーになったと申告がありました。
IEの問題なのかと、別の方がfirefoxで確認したところ、
エラーコンソールに「(ボタンクリック時のjs関数) is not defined」
と表示された
と申告がありました。

キャッシュのクリアやIEの設定のリセットなど、
いろいろやってもらったのですが
現象は発生しました。
   ↓
(※実際、<SCRIPT>外部ファイルの記述を下部に移動したら解決しました!)


今まで(過去5年間)で私はこの現象はおきたことはありません。
開発部隊からの申告も今までは何もありませんでした。
(5年前から変更のない処理になります)
今でも開発環境では発生しません。


何箇所かで動いているシステムなので
今後、IEのバージョンアップや社内LAN環境が変わったりして
同じような現象が発生すると困るので状況の把握をしておくことと
対処を調べておくよう言われています。


js関数は同じ関数名だと後から読み込まれたほうが動くと言うことですが、
例えば、今回下部に移動したjs外部ファイルの読込みSCRIPTを
上部にも、ファイル名を変えて同じ内容のjs外部ファイルの読込みSCRIPTを
記述したらどうなるのでしょう?
エラーにならなければ・・・なんて思うのですが
安易ですよね。。。


ボタンクリックのイベント処理で、js外部ファイルを読み込みますが、
(そのようにhtmlとして吐き出していますが)
その際に、読み込まれてたjs関数が一旦、
クリアされるなんてないですよね?

補足日時:2012/04/06 11:24
    • good
    • 0
この回答へのお礼

ありがとうございます。

補足に追記します。
(補足に書いていいのかわからないのですが)

お礼日時:2012/04/06 10:25

何かの勘違いの可能性が高いように思われます。



@defer や @async がない限り、外部スクリプトの読み込みはページ描画をブロックします。head 内に 6 個も 7 個も外部スクリプトを並べれば、それらが全部読み込まれるまで、閲覧者は白紙のまま待たされることになります。そうならないよう、外部スクリプトの読み込みを body の末尾に移動させるのです。

ですが、ボタンの場合は別です。ボタンが表示された時点で、ボタンが機能しなければなりません。つまり、ボタンに関する外部スクリプトはボタンの前に読み込んでおかねばならないのです(ここで「え、ボタンがまだ読み込まれていないのに?」と思った方は、バブリングを調べて下さい。まあ、準備が整うまで disabled にしておく手もありますが)。

それを踏まえれば、ボタン制御のスクリプトを事前に読み込んでおくのは真っ当な方法です。それで関数の未定義エラーが出るのなら、単純に、外部スクリプトが読み込まれていなかった可能性が高いと思われます。あるいは、他に原因があります。

この回答への補足

下記のサイトを見つけました。

http://blog.ohanasiya.net/?m=blog&eid=e6f9208db4 …

中ごろのコメントに
#また、関数を定義する順番としては
#以下のような注意点があります。

# ・HTMLのロードが完全に終わっていない状態で
#  getElementByIdなどを呼び出すと、
#  失敗してスクリプトの実行がそれ以上進まなくなる場合がある。

# ・onMousemove、onClickで指定された関数は、
#  HTMLのロードが完了した後に定義しなければならない。

とあります。
特に今回の事象の解決策はこれでした。
# ・onMousemove、onClickで指定された関数は、
#  HTMLのロードが完了した後に定義しなければならない。

これは決まりごとなのでしょうか?
W3Cの?

決まりごとであれば、無条件に従い、
次のシステムにも反映したいと思いますが。

補足日時:2012/04/04 16:47
    • good
    • 0
この回答へのお礼

ありがとうございます。

#ボタンの場合は別です。ボタンが表示された時点で、
#ボタンが機能しなければなりません。
#つまり、ボタンに関する外部スクリプトはボタンの前に
#読み込んでおかねばならないのです

これだと理解できます。
が、未定義エラー・・・になってしまったのです。

なぜか今回、下のほうに移動してしまってエラーを回避できましたが
それこそ変ですよね。
逆に・・・未定義になる可能性大???


修正前の現象では、
<HEAD>内記述の外部Scriptファイルが読み込みが終わっていないのに、<BODY>の表示が開始され、ボタンも表示されたので
ボタンをクリックした結果、未定義エラーになってしまった...
という感じになります。


#それで関数の未定義エラーが出るのなら、
#単純に、外部スクリプトが読み込まれていなかった可能性が
#高いと思われます。
#あるいは、他に原因があります

単純に外部スクリプトが読み込まれていなかった可能性って、
どういう事態でしょうか?

他の原因って 何かありますでしょうか。

5年前に開発したWEBシステムで、IE6で確認を行い、localでも、
社内イントラでもこのような事象はおきませんでした。

2年前にも同じシステムを導入し、IE8でも確認しましたが、localでも、
イントラでも事象はおきませんでした。

変わったことといえば、社内イントラ環境がバージョンアップされたのかも???くらいです。

IE6は構文エラーなどの不具合をカバーしてくれてしまうようですが、
IE8では厳しくなってそこでエラーになりますよね。
2年前のIE8ではエラーは出なかったんですが、今調べてみると、
チョロチョロと構文エラーがあります。
それでもまだ互換性モードにしているので、フォローされてるのだと思いますが。

外部ファイルには全てのJavaScript処理を記述していて、200kbくらいあります。
画面によっては関係ない処理も入っています。

これを整理して関係のある関数だけのjsファイルの記述だけにするよう、
分割したほうがいいのでしょうか?
(かなりの手直しになりそうですが)

お礼日時:2012/04/04 14:17

「外部jsファイル」の中身が問題になります。


javascriptをheadに直接書く場合、そのまま実行してしまうとHTMLの内容がロードされる前に実行されてしまう場合があります。
この時、javascript内でHTML内の要素を扱うような処理を行っていると、その部分がエラーになってしまいます。
この為、下に記述することで解決したのでしょう。

ちなみに、この順序問題は色んな解決方法が用意されています。
特にDOM要素を弄る処理が多いのであれば、jQueryを使われる事をお勧めします。
ちなみにjQueryを使用すると、「$(document).ready(function(){処理});」の書き方で、HTMLが全て読み込まれた状態から処理を開始してくれるようになる為、headに記述しても問題無くなりますよ。
    • good
    • 0
この回答へのお礼

ありがとうございます。

やはり他の要素でエラーになり、
該当関数の読込みまで処理が進まない状況だったのかもしれませんね。

その場合、その要素を扱う部分でのエラーだと理解できたのですが、
イベントを挙げた関数ではあったのですが、
なぜ、その先(!)の関数の未定義のエラーだったのでしょうか。

そこが理解できずにいます。
それともJavaScriptのエラーはそんなものなのでしょうか?
何台かのパソコンで、同じ「未定義のエラー」でした。
対応はしていないのですが、firefoxで調べてくれたときも「未定義エラー」でした。

せめて、要素を扱う処理あたりでエラーになっていてくれればわかりやすいのに。。。

すみません、もう少し
他の方のアドバイスも待ちたいと思います。

お礼日時:2012/04/02 12:02

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!