Computer Programing

2004-07


関数を使ってみよう

 関数は,「何か値を与えると,なんらかの処理が行われ,ある値を生成する」というもので,決まりきった処理の再利用性を高めるものです.たとえば数学における f(x) = sin(x)+cos(x) という関数f(x)は,x という値が入力されると,その x に対する sin(x)+cos(x) が計算され出力されるものです.JavaScript における関数もこれと同じです.

 関数を定義したいときは

function 関数名( 引数名1, 引数名2, ... )
{
   処理
}

と書きます.関数名は変数名と同じように自由につけることができます.関数名の後に続けて括弧( ) の中に関数の呼び出し側から渡される値を受け取る変数名を書きます.この変数を引数と呼びます.この変数は次に続く中括弧{ } の中に書く処理コードで自由に利用することができます. そして,値を生成したいときには return 文を使います.return 文が実行されると,関数内の処理は終了します.

 関数を呼び出すときには,

関数名( 渡す値1, 渡す値2,... )

と書きます.渡す値には引数にコピーしたい値を書きます.

 たとえば,二つの数値を受け取ると,その和を返す関数の定義は次のようになります.

function add( a, b )
{
  var wa = a+b;
  return wa;
}

ここで,変数 wa は関数 add の中だけで利用できる変数となります.そして,

val = add( 3, 4 )
document.write( val );

というコードを実行すると,関数 add の引数 a には 3 が,引数 b には 4 が代入され,関数 add が実行されます.関数 add の中では a と b の和を計算し,返します.その値が変数 val に代入され,ブラウザ上に表示されることになります.


main() って

今まで,JavaScript のコードを実行したいときには,

function main()
{
  ...
}

の ... のところに書くように教えてきました.この main() をよく見ると,関数の定義に似ていることに気が付くと思います.実はこの main() も関数だったのです.ただ,引数もなければ,値を返すための return 文も書きませんでした.このような関数もあるのです.プログラム言語によっては,このようなものを手続きと呼ぶものもあります.

そして,この関数 main() は,

<BODY onLoad="main()">

と,HTML ファイルがすべて読み込まれた後に最初に呼び出され,実行される関数として,指定してあるために,main() の中に書いた JavaScript コードが実行されていたわけです.


同じ処理ならまとめましょう.

関数はどのようなときに使えばよいのでしょうか.たとえば,次のプログラムは3点間の距離を求めるプログラムです.ここで,Math.sqrt は引数の平方根を求める関数です.

function main()
{
  var x1,x2,y1,y2,x3,y3,l1,l2,l3;

  x1 = parseInt( prompt( "1点目のX座標を入力してください", "0" );
  y1 = parseInt( prompt( "1点目のY座標を入力してください", "0" );
  x2 = parseInt( prompt( "2点目のX座標を入力してください", "0" );
  y2 = parseInt( prompt( "2点目のY座標を入力してください", "0" );
  x3 = parseInt( prompt( "3点目のX座標を入力してください", "0" );
  y3 = parseInt( prompt( "3点目のY座標を入力してください", "0" );

  l1 = Math.sqrt( (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) );
  l2 = Math.sqrt( (x2-x3)*(x2-x3) + (y2-y3)*(y2-y3) );
  l3 = Math.sqrt( (x3-x1)*(x3-x1) + (y3-y1)*(y3-y1) );

  document.write( '1点目の2点目の間の距離は', l1, 'です<BR>' );
  document.write( '2点目の3点目の間の距離は', l2, 'です<BR>' );
  document.write( '3点目の1点目の間の距離は', l3, 'です<BR>' );
}

このプログラムでは,3回点と点の間の距離を求める計算をしています.なんか,ややこしくて間違えそうです.このような複雑な処理を何度も書く場合,関数を使うとすっきりします.次が関数にした場合の例です.

function kyori( x1,y1, x2,y2 )
{
  return Math.sqrt( (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) );
}

function main()
{
  var x1,x2,y1,y2,x3,y3,l1,l2,l3;

  x1 = parseInt( prompt( "1点目のX座標を入力してください", "0" );
  y1 = parseInt( prompt( "1点目のY座標を入力してください", "0" );
  x2 = parseInt( prompt( "2点目のX座標を入力してください", "0" );
  y2 = parseInt( prompt( "2点目のY座標を入力してください", "0" );
  x3 = parseInt( prompt( "3点目のX座標を入力してください", "0" );
  y3 = parseInt( prompt( "3点目のY座標を入力してください", "0" );

  l1 = kyori( x1,y1, x2,y2 );
  l2 = kyori( x2,y2, x3,y3 );
  l3 = kyori( x3,y3, x1,y1 );

  document.write( '1点目の2点目の間の距離は', l1, 'です<BR>' );
  document.write( '2点目の3点目の間の距離は', l2, 'です<BR>' );
  document.write( '3点目の1点目の間の距離は', l3, 'です<BR>' );
}

関数 kyori は2点の座標を受け取ると,その間の距離を返すように定義された関数です.複雑な式を3回書くよりも,間違えにくくなったと思います.なお,関数の定義は基本的に,利用するよりも前に書きます.


後で利用するときも簡単です.

ある日,

var a,b,c,d,len;
a = parseInt( prompt( "1点目のX座標を入力してください", "0" );
b = parseInt( prompt( "1点目のY座標を入力してください", "0" );
c = parseInt( prompt( "2点目のX座標を入力してください", "0" );
d = parseInt( prompt( "2点目のY座標を入力してください", "0" );

と書いたところで,前に二点の距離を求めるコードを書いたことを思い出し,それをコピー&ペーストしたとします.

l1 = Math.sqrt( (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) );

この場合,l1 を len に,x1 を a に,y1 を b に...と対応する変数を探して,

len = Math.sqrt( (a-c)*(a-c) + (b-d)*(b-d) );

と,書き換える必要があります.距離の公式ならまだよいですが,もっと複雑だったら,かなり大変な作業になります.このとき,関数をコピー&ペーストするのであれば,その関数の使い方だけ覚えておけば,公式の内容などを思い出す必要がありません.いきなり,

len = kyori( a,b,c,d )

と書けばよいだけです.このように,ある処理を関数化しておくと,後で再利用するときに便利です.


こんな関数を作ってはいけません.

 関数を作るときに注意すべき点が一つあります.次のような関数は絶対作ってはいけません.

var point, num = 0, i;

function getsum( points )
{
  var i, sum = 0;
  for( i = 0 ; i < num ; i++ ) sum += points[i];
  return sum;
}

function main()
{
  num = parseInt( prompt( '人数を入力してください', '0' ) );
  point = new Array( num );
  if( num > 0 )
  {
    for( i = 0 ; i < num ; i++ )
    {
      point[i] = parseInt( prompt( '点数を入力してください', '0' ) );
    }

    // 合計点を求める
    document.write( '合計点は', getsum( point ), '点です<BR>' );
  }
}

この関数 getsum では関数外の変数 num を利用しています.しかし,関数 getsum が呼ばれるとき,num にはきちんと点数の個数が入っていますので,このプログラムは正常に動作します.しかし,このようなことをすると関数をカット&ペーストして再利用することが難しくなります.関数の中で利用する変数は,関数の中で宣言したもの,および,引数だけにしましょう.


演習

 次のプログラムは入力された4つの数値でもっとも大きい値を表示するプログラムです.

function main()
{
  var value, i, max1, max2, max;
  value = new Array(4);

  for( i = 0 ; i < 4 ; i++ )
  {
    value[i] = parseInt( prompt( (i+1)+"個目の数値を入力してください", "0" );
  }

  if( value[0] > value[1] ) max1 = value[0];
                       else max1 = value[1];
  if( value[2] > value[3] ) max2 = value[2];
                       else max2 = value[3];
  if( max1 > max2 ) max = max1;
               else max = max2;

  document.write( '最大の値は', max, 'です<BR>' );
}

まず最初に,2つの数値を与えると,大きい方の値を返す関数 maxvalue を作成してみよう.そして,main の中のコードを maxvalue を利用したものに書き換えてみよう.次のような感じになるはずです.

function maxvalue( ... )
{
  ...
}

function main()
{
  var value, i, max1, max2, max;
  value = new Array(4);

  for( i = 0 ; i < 4 ; i++ )
  {
    value[i] = parseInt( prompt( (i+1)+"個目の数値を入力してください", "0" ) );
  }

  max1 = ...
  max2 = ...
  max = ...

  document.write( '最大の値は', max, 'です<BR>' );
}