JavaScript入門 関数(function)
関数の定義方法
JavaScriptで関数を定義する方法は、主に次の2種類です。
- 関数宣言によって定義する方法
- 関数式によって定義する方法
関数宣言による関数の定義
関数宣言で関数を定義する場合は、functionキーワードに続けて関数名を記述します。関数に渡す値を引数と呼び、関数名に続く()内に設定します。関数から返ってくる値を戻り値と呼び、retrunに続けて値を設定します。
構文
function 関数名( [引数1,引数2,…] ){
関数を実行した時に実行するコード
[ return 戻り値; ]
}
関数の実行方法
・戻り値を変数に格納する場合
let 戻り値を格納する変数 = 関数名( [ 引数1,引数2,… ] );
・戻り値がない場合
関数名( 引数1,引数2,… )
関数の定義と実行
//関数の宣言
function sum( val1,val2 ){
return val1 + val2; //2
}
//関数の実行
let result = sum( 10,20 ); //1,3
console.log( result );
>30
1、関数の実行
sum( 10, 20 )のように関数名の末尾に()を付けると、関数の実行を表します。そのため、sumという名前で宣言された関数が実行されます。このとき、末尾の丸括弧()に10、20を設定しているため、これが関数sumの実行時に使う引数として渡されます。
2、関数の実行元に戻り値を返す
return文で設定した戻り値(val1 + val2)が関数を実行した結果として、関数の実行元に返されます。
3、関数の実行結果にresultに代入
代入演算子(=)によって、関数sumの実行結果が変数resultに代入されます。
引数と戻り値
引数
JavaScriptの関数宣言時に設定する引数と戻り値の基本的な特徴
- 引数は、関数の中で変数と同じように使用できる
- 引数の命名規則は、変数の命名規則に準ずる
- 引数を受ける取る必要がない関数は引数を省略できる
- 引数を複数個設定する場合には、カンマ(,)で引数同士を区切る
- 関数宣言時に設定する引数を仮引数、関数実行時に渡す引数を実引数と呼び分ける
- 関数の引数は、あくまでその関数内でのみ有効な識別子です。関数の外では引数に与えた識別子にアクセスできません。
引数が複数個ある場合には、実引数で渡した順番で仮引数に値が渡される。
実引数の個数と仮引数の個数が一致しない場合は、次のような挙動になる。
実引数は、関数内でのみ使用できる「arguments」という特殊なオブジェクトにも渡される。これは、仮引数を設定しない場合でも、実引数の値を関数内で取得できます。このように引数の個数が決まっていない状態を「可変長引数」と呼び
戻り値
JavaScriptの関数宣言時に設定する戻り値の基本的な特徴
- 戻り値は、関数内のreturn文で設定した値になる
- return文は複数記述できるが、一番初めのreturn文が呼びさだれた時点で関数処理は終了する
- return:のように記述して戻り値を設定しない場合は、undefinedが実行元に返される
- return文が関数内に存在しない場合は、関数の最終行まで処理が完了した時点でundefinedが実行元に返される
- returnによって戻り値が関数から返される場合でも、必ずしも実行文で戻り値を受け取る必要はない
「return文が実行されると、関数の処理がその時点で終了します。」そのため、if文と組み合わせて強制的に関数を終了するためにreturn文が使われることがあります。
例:
function printSum( a , b ){
//数値型以外が引数に渡されたときに関数の処理を終了
if( typeof a !== "number" || typeof b !== "number" ){
console.log("引数が不正なため関数を終了します。");
return; //このreturn文が実行されると関数の処理は終了し、呼び出し元に処理が戻る
}
console.log( a + b);
}
関数式による関数定義
関数の定義は、代入演算子を使って変数に対して関数式を代入することでも行うことができます。
構文:関数式による関数定義
const 関数名 = function ( [ 引数1, 引数2,・・・ ] ){
何らかの処理
[ return 戻り値; ]
}
構文:関数を実行する方法
let 戻り値を格納する変数 = 関数名( [引数1, 引数2,・・・] );
関数式による関数定義では、const 関数名 = function(){ ・・・ }というように関数を定義しています。関数式で定義した関数も、関数宣言で定義した関数と同じように使うことができます。
const minus = function( val1, val2 ){
return val1 - val2;
}
let result = minus( 10,5 );
console.log( result );
>5
関数宣言と関数式の違い
関数宣言と関数式のどちらで定義しても、関数の使用方法や機能に大きな違いはありませんが、次の違いがあります。
1、関数名の重複
関数宣言の場合は、関数名が重複している場合、エラーにはならず、あとから宣言されたほうの関数によって機能が上書きされます。
function test(){
console.log( "こんにちは" );
}
function test(){
console.log( "さようなら" );
}
test();
>さようなら //後に定義された関数が実行される
関数式の場合は、関数名が重複しているとエラーが発生します。
const test = function(){
console.log( "こんにちは" );
}
const test = function(){
console.log( "さようなら" ); //エラーが発生
}
これは、関数式で使っているconstというキーワードが、同じ変数名で宣言したとき(変数の再宣言時)にエラーを発生させるためです。
2、実行文の記述位置
関数宣言で関数定義を行った場合には、関数の宣言文より前に実行文を記述できます。
hell();
>こんにちは
function hello(){
console.log("こんにちは");
}
関数式で関数定義を行った場合には、関数定義より前に実行文を記述するとエラーが発生します。
デフォルト引数
JavaScriptの関数では、デフォルト引数という機能を使うことができます。デフォルト引数を設定することで、関数実行時に値が渡されなかった仮引数に対してデフォルト値(初期値)を設定できます。
構文
function( arg1 = 初期値1, arg2 = 初期値2 ){・・・}
function plus( a, b = 5 ){
return a + b;
}
//引数を1つしか渡さない場合
console.log( plus( 1 ) );
>6 //引数にいは、デフォルト引数の5の値が設定される
//引数を2つ渡したい場合
console.log( plus( 1 , 10 ) );
>11 //a = 1,b = 10で計算される
デフォルト引数の値が設定されるのは、仮引数に渡ってきた値がundefinedの場合に限ります。nullの場合にはデフォルト値による設定が行われないです。
第1引数は使わないため、第2引数のみに値を渡す
function fn( arg1 = "初期値1", arg2 = "初期値2" ){
console.log( arg1, arg2 );
}
fn( undefined, "引数2" );
>初期値1 引数2
引数が多いときは、引数にオブジェクトを渡す
引数の数が多くなった場合は、可読性が下がるためオブジェクトを渡すことで解決することができます。
function fn( obj ){
obj.arg1 ??= "初期値1";
obj.arg2 ??= "初期値2";
console.log( obj.arg1, obj.arg2 );
}
const params = { arg2: "引数2" };
fn( params );
>初期値1 引数2
引数にオブジェクトを渡すときの注意
変数に格納されているのはメモリ空間のアドレスです。そのため、オブジェクトが関数の引数として渡されたとき、関数内でオブジェクトのプロパティの値が変更されると、関数外のオブジェクトにも変更が反映されます。
const obj = { val: 1 }; //valの値に1を設定したオブジェクトを定義
function fn( obj2 ){
obj2.val = 2; //オブジェクトの値を変更
}
fn( obj ); //オブジェクト(obj)を関数(fn)の引数に渡す
console.log( obj.val );
>2
関数fnを実行するときにobjのアドレスがobj2にコピーされます。オブジェクトが保管されているメモリのアドレスがコピーされているだけなので、objとobj2は同じオブジェクトへの参照を保持しています。
一方、関数内で別のオブジェクトを変数に格納した場合は、関数外の変数が参照しているオブジェクトに影響ありません。
コールバック関数
コールバック関数とは、他の関数に引数として渡す関数のことです。JavaScriptで開発を行っているとよく使われます。
関数とは
JavaScriptにおける関数とは実行可能なオブジェクトです。関数はオブジェクトの一種であり、オブジェクト{}と異なるのは「実行可能である」という点だけです。
関数にプロパティやメソッドの追加
function fn(){} //空の関数を定義
fn.fullName = "山田太郎"; //オブジェクトのようにプロパティを追加
fn.hello = function(){ //メソッドの追加
console.log("おはよう");
}
//プロパティ取得
console.log( fn.fullName );
//メソッドの実行
fn.hello();
>おはよう
コールバック関数の仕組み
関数はオブジェクトの一種なので、オブジェクトのように他の関数の引数として渡すことができます。
構文
function fn( callback ){
通常の関数と同様に処理を記述可能
let result = callback( [ param1, param2, … ] ); //コールバック関数の実行
通常の関数と同様に処理を記述可能
}
- fn:コールバック関数を受け取る関数です。関数内でコールバック関数を実行します。
- callback:コールバック関数を受け取る引数です。他で定義された関数がこの引数に渡されます。
- param1、param2:コールバック関数は通常の関数と同じように引数を渡して実行できます。
- result:コールバック関数から戻り値を受け取ることもできます。
例
function saySomething( callback ){ //コールバック関数を受け取る関数
const result = callback(); //コールバック関数の実行
console.log( `$[result]、山田太郎` )
}
function hello(){
return "こんにちは";
}
function bye(){
return "さようなら";
}
saySomething( hello ); //コールバック関数を引数に設定して、関数を実行
saySomething( bye ); //コールバック関数を引数に設定して、関数を実行
この場合には、saySomethingに渡されたhello関数、bye関数がコールバック関数です。saySomething関数内では、渡されたこれらのコールバック関数をcallbackという引数で扱います。関数はオブジェクトの一種なので、通常のオブジェクトを引数で受け取ったとき同様に、callbackとhelloやbyeが参照している先の関数は同じものです。
saySomething( hello ); //※1
saySomething( hello() ); //※2
※1と※2の記述方法に気を付けてください。※1はコールバック関数として引数に渡していますが、※2は関数の実行結果を渡しているためエラーとなります。
コールバック関数を引数に取る組み込み関数
あらかじめJavaScriptエンジンによって準備されている組み込み関数の中にもコールバック関数があります。setTimeoutは、第1引数で渡したコールバック関数を特定の秒数だけ待ってから実行する特別な関数です。
構文:setTimeoutの記法
setTimeout( callback, [ms , param1 , param2, ・・・] );
- callback:コールバック関数を受け取る引数
- ms: 待機ミリ秒を指定する引数です
- param1、param2:コールバック関数の実行時に渡す実引数です。
たとえば、3秒後にコールバック関数の処理を実行するには、次のようにします。
function hell(){
console.log("おはよう");
}
setTimeout( hello, 3000); //3秒後に以下のメッセージが表示される
>おはよう
コールバック関数に引数を渡すパターン
setTimeoutでは、第3引数に以下を設定することで、コールバック関数に対して引数を渡して実行できます。”山田太郎”がhelloの引数nameに渡され、setTimeout内で実行されます。
function hell( name ){
console.log("おはよう" + name);
}
setTimeout( hello, 3000,"山田太郎");
>おはよう、山田太郎
無名関数を使ったコールバック関数
無名関数(anonymous function)とは、名前がない関数のことです。名前がついてる関数は、名前付き関数と呼ぶことがあります。基本的に名前付き関数は複数回呼び出されることを想定していますが、無名関数は一度しか呼び出されないようなケースに使われます。
構文
function( [arg1, arg2.・・・] ){・・・}
setTimeout(function(){
console.log( "こんにちは" );
}, 3000); //3秒後に以下のメッセージが表示される
>こんにちは
無名関数をコールバック関数以外に使用するケース
//無名関数を変数に代入
const fn = function(){}
//オブジェクトのプロパティに無名関数を設定
const obj = {
method: function(){}
}
アロー関数
アロー関数とは、ES6で追加された無名関数の省略記法のことです。たとえば、コールバック関数に使う無名関数をアロー関数に置き換える場合は、次のようにします。=>の部分がアロー(矢印)に似ているため、アロー関数と言います。
//無名関数
setTimeout( function() {
console.log("おはよう");
},1000 );
//アロー関数
setTimeout( () => console.log( "おはよう" ),1000 );
アロー関数の記法
アロー関数は、引数の個数や関数の本文の行数によって、省略できる度合いが変わってきます。
引数がない場合
//アロー関数
() => { 関数の実行文; };
//無名関数
function(){ 関数の実行文; }
引数が1つの場合
//アロー関数
引数 => { 関数の実行文; };
//無名関数
function(引数){ 関数の実行文; }
引数が複数の場合
//アロー関数
(引数1,引数2, ・・・) => { 関数の実行文; };
//無名関数
function(引数1,引数2,・・・){ 関数の実行文; }
関数の実行文が1行の場合
//アロー関数
(引数1,引数2, ・・・) => 関数の実行文;
//無名関数
function(引数1,引数2,・・・){
return 関数の実行文;
}
関数の実行文が複数行の場合
//アロー関数
(引数1,引数2, ・・・) => {
関数の実行文;
return 戻り値;
}
//無名関数
function(引数1,引数2,・・・){
関数の実行文
return 戻り値;
}
関数の実行文が1行かつ戻り値がオブジェクトの場合
オブジェクトリテラル{}を丸括弧()で囲みます。これは、アロー関数の実行文を囲む括弧{}の部分と区別するためです。
//アロー関数
(引数1,引数2, ・・・) => ({ プロパティ1:値1, プロパティ2:値2 })
//無名関数
function(引数1,引数2,・・・){
return { プロパティ1:値1, プロパティ2:値2 };
}
アロー関数と無名関数の違い
アロー関数は基本的には無名関数と同じ挙動ですが、特定のケースでは挙動が異なります。
キーワード | 無名関数 | アロー関数 |
---|---|---|
this | thisを持つ | thisを持たない |
arguments | argumentsを持つ | argumentsを持たない |
new | newでのインスタンス化が可能 | newでのインスタンス化不可 |
prototype | prototypeを持つ | prototypeを持たない |
無名関数ではargumentsを使用できる
const hello = function(){
console.log( "ハロー、" + arguments[ 0 ] );
}
hello( "山田" );
>ハロー、山田
Functionコンストラクタによる関数定義
関数は、Functionコンストラクタというコンストラクタを使って作成することもできます。コンストラクタとは、オブジェクトを作成するために使う特別な関数のことです。Functionコンストラクタは、通常は使いません。
構文
- 引数1、引数2:関数の引数名を文字列で定義します。
- 本文:最後の引数が関数の本文です。これも文字列で定義します。
const 関数名 = new Function( [ "引数1" , "引数2", ・・・, ]"本文" );
//関数addをFunctionコンストラクタから作成
const add = new Function( "val1" , "val2" , "return val1 + val2;" );
//関数(add)の実行
const result = add( 1,2 );
console.log( result );
>3
このようにFunctionコンストラクタを使って関数を作成する場合には、引数や関数の本文を文字列として定義できます。そのため、Functionコンストラクタは、動的に関数を作成することができます。ただし、一般的に関数定義は、関数宣言または関数式を使って行います。Functionコンストラクタを使う必要がある場合は、脆弱性が発生しないように注意する必要があります。
eval( "console.log( 1 + 2 )" );
>3