« サイト公開に必要なサーバとドメイン その他

データベースの文字コードを調べる MySQL »

関数名()と関数名のみの違い JavaScript

JavaScriptではイベント発生時に関数を実行させる場合、以下のように記述します。イベントに関数を代入しておき、イベント発生時に実行します。イベントに関数を設定する場合は関数名に()をつけませんね。

window.onload = 関数名;

もし下記のソースコードのように関数名に()をつけてしまうとうまく動かないことがあります。それはなぜでしょう?この疑問を検証してみます。

window.onload = 関数名(); //うまく動かないことがある

関数名()と関数名の違い

以下のソースコード1を実行するとアラートが表示され、きちんと動きます。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <meta http-equiv="Content-Script-Type" content="text/javascript" />
    <title>「関数名()」と「関数名」の違い</title>
    <script type="text/javascript">
    //<![CDATA[
      window.onload = alertMain;

      function alertMain() {
        var mainElement = document.getElementById('main');
        var mainData = mainElement.innerHTML;
        alert(mainData);
      }

    //]]>
    </script>
  </head>
    <body>
      <noscript>
        <p>このページはJavaScriptを使用しています。JavaScriptを有効にしてください。</p>
      </noscript>
      <div id="main">「関数名()」と「関数名」の違いについて検証してみる</div>
    </body>
</html>

イベントに関数を登録している10行目の関数名に()をつけるとどうでしょうか?

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <meta http-equiv="Content-Script-Type" content="text/javascript" />
    <title>「関数名()」と「関数名」の違い</title>
    <script type="text/javascript">
    //<![CDATA[
      window.onload = alertMain();

      function alertMain() {
        var mainElement = document.getElementById('main');
        var mainData = mainElement.innerHTML;
        alert(mainData);
      }

    //]]>
    </script>
  </head>
    <body>
      <noscript>
        <p>このページはJavaScriptを使用しています。JavaScriptを有効にしてください。</p>
      </noscript>
      <div id="main">「関数名()」と「関数名」の違いについて検証してみる</div>
    </body>
</html>

上記のソースコード2はアラートが表示されなくなり、JavaScriptエラーになります。さて、なぜうまく動かなかったのか検証してみることにしましょう。

window.onloadに代入されているのは?- 関数名のみ編

ソースコード1は10行目で関数名のみを「window.onload」に代入しています。

    <script type="text/javascript">
    //<![CDATA[
      window.onload = alertMain; //関数のアドレスの入った変数alertMainを代入している

      function alertMain() {
        var mainElement = document.getElementById('main');
        var mainData = mainElement.innerHTML;
        alert(mainData);
      }

    //]]>
    </script>

JavaScriptの変数には型があり、数値型(Number)や文字列型(String)などがあります。そして関数型(Function)という型も存在します。

実はalertMainは変数名であり、その変数には関数のアドレスが入っています。つまり、関数のアドレスを「window.onload」に代入し、ページを読込んだらアドレス先の関数を実行してくださいね。とお願いしているのです。なのでtypeof演算子を使ってalertMainの型を調べるとfunctionと返ってきます。

    <script type="text/javascript">
    //<![CDATA[
      window.onload = alertMain;
      alert(typeof alertMain); //typeofでalertMainの型を調べる 結果:function

      function alertMain() {
        var mainElement = document.getElementById('main');
        var mainData = mainElement.innerHTML;
        alert(mainData);
      }

    //]]>
    </script>
typeofで型を調べる

さて、ここで疑問に思うのがalertMainという変数を用意した覚えもないし、そこに関数を代入した覚えもないというところです。

    <script type="text/javascript">
    //<![CDATA[
      window.onload = alertMain;

      function alertMain() {
        var mainElement = document.getElementById('main');
        var mainData = mainElement.innerHTML;
        alert(mainData);
      }

    //]]>
    </script>

ソースコード1-1の関数定義方法だと変数に関数を代入している感があまりないのですが、JavaScriptにはもう一つ関数の定義方法があり、そちらの記述法だと変数に関数を代入していることがわかりやすいのではないでしょうか。

    <script type="text/javascript">
    //<![CDATA[
      var alertMain = function() {
        var mainElement = document.getElementById('main');
        var mainData = mainElement.innerHTML;
        alert(mainData);
      }

      window.onload = alertMain;

    //]]>
    </script>

ソースコード1-2の記述法でも関数を定義することができ、こちらの記述法だと変数alertMainに関数が代入されているとわかります。ちなみにソースコード1-2の書き方の場合は宣言した変数に関数を代入してから「window.onload = alertMain;」を記述しなければいけません。これは通常の変数の時のルールと一緒です。

ソースコード1-1のように「function 関数名() { 処理内容 }」と記述した場合は特殊で、スクリプト本体実行前に関数の定義が読込まれます。そのため関数が呼び出された後に記述しても問題ありません。

長々と書きましたが「window.onload」に関数名のみを代入した場合は、イベント発生時(今回はページ読み込み完了時)に実行する関数のアドレスを代入していることになります。

window.onloadに代入されているのは?- 関数名()編

では、ソースコード2の時はなぜうまく動かずJavaScriptエラーになったのでしょうか?実はalertMain()がページ読み込み前に実行されてしまい、13、14、15行目部分を実行する時に要素をうまく取得できなくてエラーになっています。

「window.onload」に実行する関数本体を登録したかったのですが、alertMain()と書いてしまったためにalertMain関数を実行して得た戻り値を「window.onload」に代入してしまったのです。もちろん戻り値を代入するためにはalertMain()を実行する必要があり、ページ読み込み完了前に関数が動いてしまったのです。

    <script type="text/javascript">
    //<![CDATA[
      window.onload = alertMain(); //関数を実行して得た戻り値をwindow.onloadに代入している

      function alertMain() {
        var mainElement = document.getElementById('main');
        var mainData = mainElement.innerHTML;
        alert(mainData);
      }

    //]]>
    </script>

以上の結果から、イベントに関数を設定する場合は関数名に()をつけないで記述し、関数のアドレスを渡すようにしましょう。