JavaScript 入門 関数

出典: フリー教科書『ウィキブックス(Wikibooks)』

JavaScript > 入門 関数

目次

[編集] 関数

ここまでの説明で、プログラムを記述するために必要な要素は一通り解説したが、プログラムが巨大化していくと次第に複雑になっていく。 これを避けるためには、プログラムを必要に応じて分割することが有効な事から、JavaScriptは関数を使うことによってこれを実現している。

[編集] 関数の説明

まずは、次のプログラムを見て欲しい

function f( x ){
  var a = 2*x*x + 3*x + 5;
  return a;
}
document.write( f( 5 ) );  // 2*5*5 + 3*5 + 5 の結果(70)を表示

また、プログラム中の「f(5)」の中にあるように、関数に値を送り、その結果を「return 式;」という文によって、返す事が出来る。 このように関数に対して送る値のことを、引数(ひきすう)といい、返ってくる値を返り値と言う。

(※良く間違える人がいるのですが、引数(いんすう)と読んではいけない。 いいですか! 「ひきすう」ですよ「ひ・き・す・う!」)

このように、関数は、プログラムを機能ごとに分割して、再び利用しやすい様に出来上がっている。 良く作られた関数は中でどのような処理が行われたのかを気にすることなく、どのような仕事をするのかを理解していれば十分な様に出来ている。 ちなみに、たびたび多用している「document.write()」もJavaScript側で標準で用意されている、数ある関数の一つである(正確には違うのだが、この点に関しては後の章に回す)

関数は、この性質のために、行う仕事ごとにプログラムを構造的に分ける効果があり、そのため再利用しないルーチンであっても、ただ単にプログラム全体の見通しを良くするために関数ごとに切り分けることが良くある。 つまりは

function f(){
  文1;
  文2;
  文3;
  文4;
  文5;
  文6;
}

と、関数の中で多くの処理を記述しているときに、

function g(){
  文1;
  文2;
  文3;
}
function h(){
  文4;
  文5;
  文6;
}
function f(){
  g();
  h();
}

の様に、処理ごとに切り分けて見通しを良くしておくことが出来る。

[編集] 通用範囲(Scope)

関数を使って、プログラムの機能を有効に切り分けるには、関数をブラックボックスとして、外側から操作できないようにする必要があるが、このための仕掛けを局所化(localization) と言う。

次のプログラムを見て欲しい

var foo="関数の外";

function f(){
  var foo="関数の中";
  document.write( foo + "<br / >" );	//「関数の中」が表示される
}

f();
document.write( foo, "<br / >" );	// 「関数の外」が表示される

関数の中と外で、同じ名前の変数を宣言しているが、document.write()で表示された値は、それぞれでちゃんと違っている。 このように、関数の中と外で宣言された変数は別のものとして扱われることで、関数の中の機能を独立させている。 ちなみに、宣言した変数が使える範囲の事をスコープ(通用範囲)と言う。 JavaやC++などの場合は、ブロック({})で囲まれた範囲がスコープとなるが、JavaScriptの場合は関数の終わりまでになる。

(例外としてwith文中ではスコープが働くが、これは後述する)

[編集] 再帰構文(Recursion)

関数は自分自身を関数内部で直接呼び出すことが出来る。 これを再帰と言い、for文とは違った方法で繰り返しの計算を行うことが出来る。

次のプログラムは、与えられた自然数nに対して、その階乗を返す。

/* nの階乗を計算します */
function factorial( n ){
  if( n<=1 ) return n;
  return n * factorial( --n );
} 

この様に、for文を使うよりも短い形で、アルゴリズムを実装できる場合がある。 再帰構文は、for文と比べると、若干人間の直感から外れるが、for文などで処理しようとすると大変複雑になる場合もコレを使うと大変スマートな形で収まることが良くあるので、覚えておくと良い。

次のプログラムは、指定されたオブジェクトを文字列として出力する関数である。 三項演算子など、解説を後に回している構文を使っているので後の項を学習してから読み直して欲しい。

/**
 * 与えられたオブジェクトを連想配列書式の文字列に直します
 * (Firefoxの場合unevalという類似の関数があるが、英語圏以外の文字の扱いに問題がある)
 */
function ObjToJSON( o ){
  var arr = [];
  for( var i in o ){
    var to=undefined;
    if( !o.hasOwnProperty(i) ) continue; // 親オブジェクトから継承したものはパス
    if( 'object'==typeof o[i] ) to = ObjToJSON( o[i] );
    if( 'string'==typeof o[i] ) to='"'+o[i].replace(/\"/g, "'")+'"';
    arr.push( (o instanceof Array)?to : i+' : '+to );
  }
  return (o instanceof Array)?'[ '+arr.join(' , ')+' ]':'{ '+arr.join(' , ')+' }';
} 

[編集] 余談:構造化プログラミング

コンピューターは、その邦訳の通り、電子計算機である。 その計算、処理の過程は

  • 逐次処理
  • 条件分岐(if文など)
  • 反復(for文等)

の3つの行動を行うことで行われる。昔はこれだけで良かったのだが、コンピューターが高性能化し、プログラムが巨大化すると、プログラムを切り分けてその複雑さを軽減する必要が出てきた。 そのために考えられたのが関数という考え方である。

ヘルプ