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

Internet Explorer の右クリックメニューに登録するスクリプトを作っています。

たとえば、いま表示しているページのURLを表示する場合、

<script type="text/javascript">
var parentWindow = window.menuArguments;
var URL = parentWindow.document.URL;
window.onload = function() {
  kansuu(URL);
};

kansuu = function(url) {
  alert(url);
}
</script>

↑は動きます。

また、

var parentWindow = window.menuArguments;
var URL = parentWindow.document.URL;
window.onload = kansuu(URL);

function kansuu(url) {
  alert(url);
}

↑も動きます。

ところが、

var parentWindow = window.menuArguments;
var URL = parentWindow.document.URL;
window.onload = kansuu(URL);

kansuu = function(url) {
  alert(url);
}

は動きません。

なぜでしょうか?
理由を教えていただけると嬉しいです。

よろしくお願いします。

A 回答 (5件)

> よく「onload は DOM 木を全て読み込んだ後で実行される」と聞きますが、違うのでしょうか?


これ自体は正しいです。

しかし、window.onload = kansuu; と書いたときの話で、window.onload = kansuu(URL); と書いたときに
kansuu(URL) の実行を DOM 木の読み込みが終わるまで待ってくれる訳ではありません。

以下の例を実行してみてください。

function func() {
alert("関数が呼ばれました。");
}

var f;

alert("f = func;");
f = func;
alert("f = " + f);
alert("f();");
f();

alert("f = func()");
f = func();
alert("f = " + f);
alert("f();");
f();
// f には何も入っていないので、エラーが発生します。
// (window.onload は何も入っていないときは実行されないので window.onload に何も入っていないときには
// 特にエラーは発生しません。

これを実行すると、
1. 「f = func;」と表示される
2. f = func の行では何も表示されない (func() は実行されていない)
3. f = function () { ... } と表示される (関数が代入されている)
4. f(); を実行すると、f = func; で代入した func(); が実行され、「関数が呼ばれました」と表示される

5. 「f = func();」と表示される
6. f = func(); の行で「関数が呼ばれました」と表示される (この時点で func() は実行されている)
7. 「f = undefined」(ここでは、 fには何も入っていない、と思ってください)と表示される
8. f(); の行では f に何も入っておらず、何も表示されない
(func()は実行されていない。ブラウザによってはエラーが表示されるかもしれません)

となります。これと同様に
・window.onload = kansuu; と書けば DOM 木が読み込まれた時点で kansuu が実行される
・window.onload = kansuu(URL); と書けば、この行で kansuu(URL); を実行し、
DOM 木が読み込まれた時点では何も実行されません。



> onload の時点では、
> kansuu = function (url){} の代入は行われていませんが、
> なぜ動くのでしょうか?

kansuu(URL); を実行しようとした時点では kansuu に値が入っているので、問題ありません。

1. window.onload = function () { ... }; で window.onload に関数(「関数1」と書くこととします)が代入される。
2. kansuu = function (url) { ... }; で kansuu に関数(「関数2」と書くこととします)が代入される。
3. DOM 木の読み込みが完了する。
4. ブラウザが window.onload に指定された関数(関数1)を実行する
5. 関数1で kansuu(URL); を実行しようとしたときには kansuu には関数2が代入されているので、
 関数2を実行する。
6. 関数2でURLが表示される。

window.onload = function () {
alert(num);
};

num = 123;

としたとき、num = 123; が実行されて num に 123 が入ったあとに window.onload が実行されて
「123」と表示されるのと同じです。
    • good
    • 0
この回答へのお礼

よくわかりました。
ありがとうございました。

お礼日時:2014/04/18 18:19

ANo3です。



<例1>の説明が不正確でした。
正しくは、
1行目でonloadのハンドラとして、function kansuを呼ぶ匿名関数が設定される。
ですね。
    • good
    • 0
この回答へのお礼

ありがとうございました。

お礼日時:2014/04/18 18:19

よこからですが…


ANo1様がすでに回答なさっている通りなのですが、よく理解なさっていないようなので…

>onload は DOM 木を全て読み込んだ後で実行される
その通りですが、質問者様の解釈に一部誤解があるようです。
細かく言うと、「onload時にonload eventが発生し、event処理の関数が(設定されていれば)実行される」ということになります。
一方で、ご提示のスクリプトが実行されるのはロード中で、上記のイベント処理関数を定義するところで問題が生じているということになるかと思います。

以下の違いをANo1様の説明と照合しながら確認してみてください。
簡単な説明を付けましたが、ほとんどがロード中に実行されるスクリプトの動作説明です。(ロード後ではありません)
<例1>
window.onload = function(){ kansu("test"); };
alert(window.onload);
function kansu(word){ alert(word); };
1行目でonloadのハンドラ(関数)としてfunction kannsuが設定される。
2行目では「function(){ kansu("test"); }」と表示されるはず。
(onload時にkansuが実行されます。)

<例2>
window.onload = kansu("test");
alert(window.onload);
function kansu(word){ alert(word); };
1行目でkansuが実行され、「test」が表示される。(返り値はundefinedなのでonloadのハンドラとしては何も定義されない)
2行目の処理はブラウザによって異なるようです。nullやundefinedが表示されたり、1行目でエラー扱いとなって2行目以降は動作しない場合などいろいろあるようです。
(onload時には、設定がないので何もしません。)

<例3>
window.onload = kansu("test");
var kansu = function(word){ alert(word); };
1行目でkansuを実行しようとするが、未定義なのでエラーとなる。
(onload時には、設定がないので何もしません。)

<例4>
var kansu = function(){ alert("Hellow"); };
window.onload = kansu;
alert(window.onload);
2行目でイベントハンドラとしてkansuが設定される。
3行目では「function(){ alert("Hellow"); }」と表示される。
(onload時には、kansuが実行され「Hellow」と表示される。)
    • good
    • 0
この回答へのお礼

ありがとうございました。

お礼日時:2014/04/18 18:19

javascriptの原則は


・function宣言された関数は先に評価される
・スクリプトは上から順に評価される

なので
kansuu=function(){}
を書く前にkansuuを参照しようとしても無理

たとえば
<script>
kansuu(1);
kansuu = function(num) {
alert(num);
}
</script>

はNGだけど

<script>
kansuu = function(num) {
alert(num);
}
kansuu(2);
</script>

ならいける

#1さんの指摘にもあるとおり
window.onload = kansuu(URL);
はありえない

<script>
window.onload=function(){kansuu(3)};
kansuu(4);
function kansuu(num) {
alert(num);
}
</script>


<script>
window.onload=kansuu(3);
kansuu(4);
function kansuu(num) {
alert(num);
}
</script>

の実行される順番がなぜちがうか理解した方がよいでしょう

前者はonload時に実行していますが
後者は、単純に上から順番にスクリプトを実行しているだけなので
onloadにはkansuu(3)を実行した結果が設定され、実際にonload時には
なにもされていない
    • good
    • 0
この回答へのお礼

ありがとうございました。

お礼日時:2014/04/18 18:20

まず、以下の点にご注意ください。



・function kansuu() { ... } と直接書くと全体で kansuu の名前は有効になります。

・kansuu = function () { ... }; とした場合は、代入した後でしか関数は利用できません。
hoge = 1; という文があったとして、hoge = 1; とする前に hoge の内容を表示しても 1 ではないのと同じことです。

ということで、上記のスクリプトはそれぞれ

■ window.onload = function () { ... }; としたとき
window.onload で指定した関数が実行されるときには、
kansuu = function () { ... }; を通過した後なので、
kansuu の内容が実行されます。

■ function kansu() {} とした場合
kansuu はどこからでも参照できますので、window.onload = kansuu(URL); は有効です。
ですが、予想した通りに動いているとは思えません。

window.onload = kansuu(URL); とした場合、以下のように動作します。

1. window.onload の行に来た時点で、kansuu(URL) を実行します。 (まだ読み込みは完了していない)
2. kansuu は戻り値を返していないので undefined が返却される
3. window.onload のタイミングでは何もしない

ということで、読み込まれる前に kansuu は実行されますが、問題はないですか?

window.onload = kansuu; と window.onload = kansuu(URL); では
関数自体を代入するのと、関数の戻り値を代入するという違いがあります。

■ window.onload = kansuu(URL); とした場合
kansuu = function ... が代入される前に読み込んでいるので、値がありません。

foo = bar;
bar = 1;

として foo に 1 が代入されないのと同じことです。

window.onload = ... の前に kansuu = ... を持ってくれば 2 つ目と同じ振る舞いをします。
(やはり、window.onload は何もしませんが)

この回答への補足

回答ありがとうございます。
次のところがよくわかりません。

>window.onload = kansuu(URL); とした場合、以下のように動作します。
>1. window.onload の行に来た時点で、kansuu(URL) を実行します。 (まだ読み込みは完了していない)
>2. kansuu は戻り値を返していないので undefined が返却される
>3. window.onload のタイミングでは何もしない
>ということで、読み込まれる前に kansuu は実行されますが、問題はないですか?

よく「onload は DOM 木を全て読み込んだ後で実行される」と聞きますが、違うのでしょうか?

だからこそ私の挙げた1番目と2番目のスクリプトが動くのだと思っていました。

>■ window.onload = kansuu(URL); とした場合
>kansuu = function ... が代入される前に読み込んでいるので、値がありません。

とありますが、私が挙げた1番目のスクリプトでも、
onload の時点では、
kansuu = function (url){} の代入は行われていませんが、
なぜ動くのでしょうか?

すみませんが、もう少し整理して教えていただけると助かります。

補足日時:2014/04/03 04:22
    • good
    • 0
この回答へのお礼

ありがとうございました。

お礼日時:2014/04/18 18:20

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