JavaScript|Function
JavaScript における関数
CONTENTS
はじめに
関数とは処理機能の集合体で、それを呼びだすことで、一連の処理を一括して実行することができます。JavaScript の技術仕様では、関数はオブジェクトの特殊なものとして位置付けられています。
中学・高校の数学で登場する「関数」を思い出して下さい。関数とは、
「(入力データを受け入れて)・何らかの処理を施して・(結果を返す)」
というはたらきをする存在であるといえます。
y = f(x) ( 例えば y = 2x + 1 )
は、入力データ x を受け入れて、これに処理 f( ) つまり「2倍して1加える」を施して、その結果を y として返す・・・という意味です。
- この関数の定義をJavaScriptで書くと
function f( x ){ var y = 2*x + 1; return y; }
となります。
- この関数を使うには、プログラム中で、
y = f(5);
などと書きます。
入力データの値を2倍して1加えた値、すなわち11が y にセットされます。
システム全体が親会社だとすると、個々の関数は、
親会社からデータを受け取って、それを処理・加工して、親会社へ戻す
子会社の役割を担うもの、と例えることができます。
関数の定義
function func( ... ) { ...... }
関数は、通常以下のように記述して定義します。
function 関数名([引数1 [, 引数2 [, ……]]) { [関数内で実行される任意の命令……] }
例
function add(x, y) { var z = x + y; return z; }
関数の利用
データを引数として渡して、結果をもらう・・・というのが普通です。
var ans = add(3,2);
以下のように記述すると、計算結果の5がアラートボックスに表示されます
alert( add(3, 2) );
関数の様々な呼び出し方
- ボタンから呼び出し
<input type="button" value="テスト" onclick="my_function()" />
- リンクから呼び出し
<a href="javascript:my_function();">
- 一般的なプログラムシーケンス内での呼び出し
alert( my_function(data) ); var ans = my_function(data);
関数名について
JavaScriptでは、関数は「第1級オブジェクト(ファーストクラスオブジェクト)」(変数への割り当て、計算処理などプログラミングの基本機能が使える対象)という扱いになっているので、関数名は変数名と同様のもので、別の変数に関数を渡すような扱いも可能になります。
例えば以下は「変数 add に『2つの引数の値を加えてリターンする関数オブジェクト』が格納された」 という意味になります。
function add(x, y) { var z = x + y; return z; }
ちなみに、以下のように書くとアラートボックスには、関数のソースがそのまま表示されます。
alert(add); // 括弧はつけずに名前のみ渡す
この関数は、別の変数に渡すことができるので・・
const myFunc = add; // 括弧はつけずに名前のみ渡す console.log(add(1, 2), myFunc(1, 2)); // どちらも 3 が表示されます
JavaScriptの標準関数でも可能です。
const myMax = Math.max; // max関数をmyMaxという変数に入れる console.log(Math.max(1, 2), myMax(1, 2)); // どちらも 2 が表示されます
例えば、プログラムの中途で
add = 0;
などと記述すると、addは単なる数値が格納された変数になり変わります。
無用な混乱を避けるため、変数と関数はしっかり区別する必要があります。
無名関数
var 変数 = function( ... ){ ...... }
関数名を定義せず、関数の定義と同時に変数に引き渡すと、変数が関数と同様の振る舞いをします(変数が関数になります)。
var sample = function(){ alert("abcde"); }
呼び出し方は以下のとおり
sample(); // abcde
無名関数は「関数式(関数リテラル)」ということがあります。
リテラルとはもともと「プログラムのソースコードにおいて使用される、数値や文字列を直接に記述した定数のこと」で、関数リテラルはそれらと同様に、「変数に代入する」ことができます(上の例では変数sampleに代入)。
付記:「巻き上げ」について
一般的な関数定義と変数に代入する無名関数の大きな違いは「巻き上げ」の有無です。前者は、関数の定義が呼び出し側の後に記述されていても「巻き上げ」によっ動作しますが、後者(無名関数)の場合は後者は「巻き上げ」が生じないため、関数の定義を先に記述する必要があります。以下事例です。
- 通常の関数定義の場合
console.log(greeting('Smith')); function greeting(name) { return 'Hello ' + name + ' !'; }
実行結果Hello Smith !
- 無名関数の場合|関数を後に書く場合
console.log(myFunc('Smith')); const myFunc = function (name) { return 'Hello ' + name + ' !'; }
実行結果|エラーUncaught ReferenceError: can't access lexical declaration 'myFunc'・・
- 無名関数の場合|呼び出し側を後に書く場合
const myFunc = function (name) {return 'Hello ' + name + ' !';
}
console.log(myFunc('Smith'));
実行結果Hello Smith !
即時関数
( function( ) { ...... } )( )
関数定義と関数呼び出しをまとめて行うことができる書き方です。
( function(name) { console.log( 'Hello', name, '!' ); })('Smith');
実行結果は以下。
Hello Smith!
これは、以下のように書くのと同じこと(つまり、関数を定義して、その場で即実行と同じこと)にとなります。
function sample(name) { console.log( 'Hello', name, '!' ); } sample( 'Smith' );
JavaScriptでは、関数の後に書かれる ( ) は、関数を実行するトリガーとして機能している・・と考えることができます。ソースコード全体を即時関数をラッピングすると外部環境の汚染を防ぐことができるので、その意味では重要な存在です。
標準関数(標準組込みオブジェクト)
文字列操作や数値計算に関わる定義済みの関数などについては、Web上に多くの資料があります。