とあるDTPオペレーターのInDesignスクリプト備忘録

デザイナー上がりですがいまはDTP命。InDesign用スクリプトの解説などを綴っています。読者登録して戴けると励みになります。

【入門者向け⑪】関数間のデータのやりとり(引数で値を渡す)

以前の記事で関数の説明をしましたが、そのときは初歩の初歩ということで「よく使う処理を関数化する方法と、その呼び出し方」くらいしか書きませんでした。
今回は「呼び出し元と呼び出す関数のあいだでのデータのやりとり」について説明したいと思います。

正直、私はこの辺のことを理解するのに少し時間が掛かりました。
なんのためにデータのやりとりをするのか」がよくわからなかったというのもあります。
なのでその辺のことを分かりやすく説明できたらいいなと思っています。

次のスクリプトをご覧ください。

[例1]とあるラーメン屋
/////本部/////
var men = "麺";
var soup = "スープ";
var chashu = "チャーシュー"
tokyoHonten ();//関数「東京本店」を呼び出し

/////ここから「東京本店」/////
function tokyoHonten  () {
    oomiyaTen ();//関数「大宮店」を呼び出し
}

/////ここから「大宮店」/////
function oomiyaTen () {
        alert (soup);
    }

関数の外側(トップレベル)…つまり関数を使わないときにスクリプトを直接打ち込んでいく場所を仮に「本部」と呼びます。
あくまで説明用なので、間違っても日常でJavaScriptの話をしているときに本部などと言わないでくださいね。
そして本部の下には「東京本店」という関数と、「大宮店」という関数があります。

本部は「麺、スープ、チャーシュー」という材料を変数として宣言し、そのあとに「東京本店」関数を呼び出し、東京本店関数は「大宮店」関数を呼び出しています。
大宮店は変数「soup」をアラートし、その内容を確認します。ちゃんと「スープ」というメッセージが表示されましたね。
本部が「これを使え」と言って(宣言して)いるんだから当然ですね。

では次の場合はどうでしょうか。

[例2]材料の管理が本部から東京本店に移管された
tokyoHonten ();

function tokyoHonten  () {
    var men = "麺";
    var soup = "スープ";
    var chashu = "チャーシュー"
      oomiyaTen ();
}

function oomiyaTen () {
        alert (soup);
    }

[例1]と違うのは、材料の宣言をしている場所が本部ではなく「東京本店」の関数内になったこと。本部は単に本店を呼び出しているだけですね。
そして本店は「大宮店」を呼び出し、大宮店は[例1]同様「soup」の中身を確認しました。
実行すると…アレアレ?

soupは未定義です」というエラーと同時にスクリプトが中断されてしまいました。

「うっそーん! 東京本店でsoupを定義してるじゃん!」と怒りたくなりますが、これは仕方ありません。

関数内で宣言した変数は、関数内でしか有効でない

のです。こうして関数内で宣言された変数を「ローカル変数」と呼びます。
テレビのローカル放送局みたいな感じですかね。
そしてトップレベルである「本部」で宣言した変数は「グローバル変数」と呼ばれ、本店や支店とも共有することができます。

たとえば長ーいスクリプトを書くときに関数が10個くらいあったとしても、関数内で宣言した変数は関数内でのみ有効なので、「別な関数と変数がかぶらないようにしなきゃ」なんて気にする必要がないのです。
東京本店のsoupの中身が「鶏ガラ」で、大宮本店のsoupの中身が「豚骨」だったとしても、たがいに影響し合うことはないのです。

ただ、すべての関数内で変数を共有したいときは困ります。
じゃあ一切合切を「本部」で管理してしまえばいいじゃんという話ですが、「変数の中身がずっと固定されている」ならそれでいいのかもしれません。
しかし得てして変数はスクリプトの実行中にその中身が変化するもの……本部だけで変数を管理しようとすると、関数内で変数の内容が変化したときに対応できなくなります。

なので、「関数のあいだで正しく変数をやりとりするためには、データを受け渡す方法を知らなくてはならない」のです。
その方法を書いていきます。

東京本店で宣言した材料は、次のように大宮店に「渡す」ことができます。

oomiyaten (men,soup,chashu);

大宮店を呼び出すときに、カッコの中にカンマ区切りで変数を入れてるのですね。このカッコの中身に入れた値を「引数(ひきすう)」と呼びます。
そして、大宮店は次のようにこれらを「受け取り」ます。

function oomiyaten (men,soup,chashu) {

関数の一行目、関数名のあとのカッコの中にカンマ区切りで引数を入れてるわけですね。
まとめて書くとこうです。

[例3A]
tokyoHonten ();

function tokyoHonten  () {
    var men = "麺";
    var soup = "スープ";
    var chashu = "チャーシュー"
      oomiyaTen (men,soup,chashu);
}

function oomiyaTen (men,soup,chashu) {
        alert (soup);
    }

実行してみましょう。今度はちゃんと「スープ」というアラートがされましたね。
本店で使用していた変数が、大宮店に引数として「渡された」からです。
こうして受け取った引数もまた、関数内でローカル変数として扱われるようです。

ただこういう場合はどうでしょう。
大宮店は麺のことを「そば」、スープのことを「汁」、チャーシューのことを「ブタ」と呼びます。なのでこんな風に書いてみました。

[例3B]
tokyoHonten ();

function tokyoHonten  () {
    var men = "麺";
    var soup = "スープ";
    var chashu = "チャーシュー"
      oomiyaTen (men,soup,chashu);
}

function oomiyaTen (soba,siru,buta) {//←★ココ★
        alert (siru);
    }


呼び出し元と呼び出し先とで引数の名前が違います。ためしに実行してみると……

なんとびっくり! ちゃんと「スープ」とアラートされました。
じつはこのパラメーターの受渡しは、引数の順番どおりにデータを渡しているだけで、その名前自体は比較していないのです。

ちなみに引数の数が合わなくてもエラーは出ないようです。また、使わない引数が入っていてもエラーは出ません。
余分な引数は単純に切り捨てられたり、「undefined」という未定義値が代入されたりします。
なので「使うかどうか分からないけど一応渡せる(受け取れる)状態にしておく」ことも可能なのですね。

ちなみに、次のように渡すことも出来ます。

[例3B]

tokyoHonten ();

function tokyoHonten  () {
      oomiyaTen ("麺","スープ","チャーシュー");//←★ココ★
}

function oomiyaTen (men,soup,chashu) {
        alert (soup);
    }

値を直接引数として渡しているのですね。東京本店で変数宣言する必要すらなくなりました。この渡し方をすれば、変数だけでなく様々な値を渡すことが出来るのです(値のひとつとして変数も渡せる、というのが正しい言い方かもしれません)。
ややこしく思えるかもしれませんが、こうした仕様でなければ関数間でかなり慎重に変数名などを扱わないといけなかったと思うので、値や計算結果などをこうしたかたちで受渡しできるのはありがたいですね。

次回は「データの戻し方」を説明しようと思いまする…