この記事では、JavaScriptの関数・関数式およびアロー関数の基礎構文について学習します。
JavaScriptで利用できる関数にはさまざまな種類があります。
全てをここで紹介は難しいですが、ほとんどの関数動作を学んでいきましょう。
関数は、特定のタスクを実行するコードのブロックとなります。
何かしらの図などの機能を作成して色を付けたりするプログラムを作成する必要があるとします。
まず問題を解決するために2つの関数を作成できます。
図を描く関数と図に色を付ける関数
1つの複雑な問題を小さな機能によって分割すると、プログラムが理解しやすくなり、再利用しやすくなります。
メイン機能プログラムとは別に保持および保守できます。
関数はより移植性が高く、デバッグが容易で再利用可能なコードパッケージを作成する方法を提供します。
利点
• コードの再利用性(保守)
一度作成された関数は何度でも使用できるため、関数内で行われた変更は、すべての場所で自動的に実装されます。
コーディングの節約にもなります。
• エラーの修正
プログラムを関数に分割するとエラーが発生した際、エラーの原因となった関数とその場所が明確にわかります。
ですのでエラーの修正がはるかに簡単となります。
• コンパクトになる
関数を作成するとプログラムがコンパクトになります、一般的なタスクを実行するために毎回多くのコード行を記述していく必要はありません。
本日は通常の関数だけでなくJavaScriptのアロー関数についてもすべて学びます。
最新のES6のアロー構文の使用方法と、コードでアロー関数を使用するときに注意するべき一般的な間違いのいくつか、そして通常の関数との違いを示します。
それらがどのように機能するかを見ていきましょう。
関数の宣言と呼び出し
通常の関数を宣言するための構文は下記の通りとなります。
function functionName () { // 関数の内部、実行するコード }
JavaScriptの関数は0個以上の引数を取る事できます。
カンマ繋ぎでスペースを空けて記述します。
function functionName (test1, test2, test3) { // 関数の内部、実行するコード }
まずは引数なしの簡単な例を見てみましょう。
関数の宣言は、『functionキーワード』で始まり作成する『関数の名前』、『括弧()』、最後に関数のコードを『波括弧{}』で囲みます。
関数の名前を付ける基本的なルールは、変数に名前を付ける時とほぼ同様で似ております。
変数の時と同様、分かりやすい名前を書く事をお勧め致します。
そして関数の本体は内側{}に記述されます。
function greet() { alert("Hi, Hello!!"); }
上記のプログラムでは、『greet()』という名前の関数を宣言しました。
その宣言した関数を使用するには、それを呼び出す必要があります、すごく簡単です。
function greet() { alert("Hi, Hello!!"); } greet(); // 関数の呼び出し
名前の後に括弧()を入力することにより、どこからでも呼び出すことが可能となります。
関数リターン(戻り値)
returnを使用し、値を関数呼び出しに返すことができます。
値は配列やオブジェクトなど、任意のタイプにすることが可能です。
returnは関数処理が終了した事を示します。
前述した通りJavaScript関数には0個以上の引数を取る事が可能です。
引数とは関数を呼び出す際に渡す『値』です。
その渡された値に対し処理を行い、処理された結果を返すという事になります。
例えば、引数の値を数値にしその値の処理を行い計算をします。
計算された値の結果を返します。
返ってきた値を『戻り値』と言います。
単純な足し算でみてみましよう。
function getNum(num1, num2) { let total = num1 + num2; return total; } console.log(getNum(1, 2)); // 3
上記のプログラムでは、数値の合計の結果はreturnを使用する関数によって返されます。
そして、その値の結果は変数に保存されます
function greet(foo1, foo2) { let total = foo1 + foo2; return total; } console.log(greet("Hi,", "Hello!!")); // Hi, Hello!!
何も返されない場合の関数はundefinedの値を返します。
関数は、それぞれ各小さなタスクが関数によって分割されるため、プログラムを簡単にします。
そして関数はコードの再利用を可能にし、一度宣言して複数回使用することができます。
関数を別の変数として格納しコピーする事が可能です。
数値の計算をする関数を別の変数へコピーします。
function greet(foo1, foo2) { let total = foo1 * foo2; return total; } let func = greet; // copy console.log(func(6, 6)); //36 console.log(greet(6, 6)); //36
下記は文字列になります。
function greet(foo1, foo2) { let total = foo1 + foo2; return total; } let func = greet; // copy console.log(func("Hi,", "Hello!!")); //Hi, Hello console.log(greet("Hi,", "Hello!!")); //Hi, Hello
greet関数を『func』という変数にコピーします。
出力は同じ結果となります、つまり両方として呼び出しが可能です。
関数式(無名関数)
前述の関数を作成するために使用した構文は、関数宣言と呼ばれます。
別の構文があります。
関数式が変数に格納されると、その変数を関数として使用できます。
JavaScriptでは関数を『式』として定義が可能という事です。
let x = function(num) { return num * num }; console.log(x(2)); // 4 let y = x(3); console.log(y); // 9
変数『x』に関数を格納しております。
これで関数は式として扱われる事になります。
関数式では名前を省略できます、この構文では無名関数と言います。
この場合では呼び出しは関数ではなく変数名を使用して呼び出されるのでご注意下さい。
関数宣言の閉じ波括弧{}の後にはセミコロン『 ; 』を付ける必要はありません。
ただし関数式は常にセミコロンで終了する必要がありますので忘れないように記述して下さい。
関数宣言と関数式の構文は非常に似ているので、紛らわしかもしれませんが、それぞれ評価が異なります。
どのように異なるのか見てましょう。
declaration(); // 実行される function declaration() { console.log("関数宣言"); } expression(); // typeError let expression = function() { console.log("関数式"); };
関数式では呼び出されたときに例外のエラーをスローしました。
ですが関数宣言は問題なく正常に実行されています。
これはプログラムが定義される前に関数を呼び出すかどうかは特に問題ではありません。
JavaScriptの関数は裏側で現在のスコープの最上位に引き上げます。
つまり関数式では変数に割り当てられるまで評価される事はありません。
ですので呼び出されたときはまだ関数が定義されていない事になります、それでエラーがスローされます。
言い換えると、関数式では実行が到達したときに作成され、その瞬間からのみ使用可能となります。
関数宣言は、定義されているよりも早く呼び出せます。
本来のプログラムは上から順番に実行されていきますこれは同期処理と言われますが、関数式が定義されているよりも先に実行している為、関数式ではエラーとなります。
expression(); // typeError let expression = function() { console.log("関数式"); }; expression(); // 正常に実行
このように関数宣言と関数式では異なる挙動があります。
これを理解するにはスコープまたは(可変スコープと呼ぶ)の概念を学ぶ必要があります。
スコープは以前、変数入門で記事にしましたのでそちらを参照下さい。
アロー関数
ではアロー関数での書き直しです。
アロー関数はES6またはECMAScript2015の仕様により導入された比較的新しい機能です。
アロー関数は常に『式』となります、表記は矢印表示の記号となりこれは弓矢の矢のように見える事からアロー関数と呼ばれます。
これは構文的に通常の関数式に代わるものです。
先程の関数式のように変数または定数を使用し格納します。
returnや波括弧を削除し簡潔にする事が可能です。
const getNum = (num1, num2) => num1 + num2; console.log("Calculation result: " + getNum(1,1)) // Calculation result: 2
functionキーワードと同じ関数を書いてもアロー関数の場合はシンプルかつ1行で簡潔します。
ご覧の通りfunctionキーワードと違いreturnや波括弧{}がありません、これは暗黙のリターンとも呼ばれます。
しかし、アロー関数での暗黙のリターンには落とし穴があります、コードの可読性に十分注意して下さい。
returnキーワードが必要な場合もあります。
例えば、複数の式または複雑な関数の作成が必要だったりその場合は通常の関数の時と同様にアロー関数でも波括弧{}で囲ってreturnで値を返すのに使用します。
またはオブジェクトを扱ったりする場合です。
アロー関数はより短くそしてより簡潔なコードを書くことを目的としています。
また引数が1つしかない場合は、値を囲む括弧()を省略して、さらに短縮することができます。
// let num = (n) => let num= n => n * 2; console.log( num(3) ); // 6
引数がない場合は、括弧は空ですが記述は必要です。
let x = () => "Hello"; console.log(x()); //Hello
アロー関数で動的に作成する場合は下記のようにします。
let age = prompt("What is your age?", 20); let greetings = (age < 19) ? () => alert('Hello!') : () => alert("Hi"); Greetings(); //実行
最初は目が慣れるまで読みにくいかもしれません、ですが書いていればすぐに目が適応してきて慣れてきます。
現代のES6の式はこのアロー関数を使用した記述が主流となっております。
• functionキーワードは必要なし
• returnは不要
• 波括弧{}はなくても問題ない
アロー関数に名前を付ける事はできません、アロー関数は全てが無名関数となります。
ですがES6からは、変数とメソッドなどはプロパティを使用して無名関数の名前を推測する事なら可能です。
つまり関数の識別です。
anonymousArrowFunc.nameを使用します。
const anonymousArrowFunc = () => "Hello" console.log(anonymousArrowFunc.name); //anonymousArrowFunc
この推測されたnameプロパティは、無名関数が変数に割り当てられ定義されている場合のみに存在します。
無名関数をコールバックとして使用した場合は、機能致しません。
関数オブジェクト
関数を使用してオブジェクトを返すには、様々な方法がございます。
まずは通常の関数から見ていきましょう。
オブジェクトを返す為の『returnObj』関数を作成します。
関数内部には『myObj』のオブジェクトを作成します。
function returnObj(){ let myobj = { "name": "Taro", "age": 30, "city": "TOKYO" } return myobj; }; let Obj = returnObj(); console.log(Obj); /* { "name": "Taro", "age": 30, "city": "TOKYO" } */
returnでオブジェクトを返します。
関数を呼び出す必要があります、呼び出す関数をObjという変数に割り当て、関数が返すオブジェクトは全てObjに格納されています。
次は無名関数からオブジェクト返す例を見てみましょう。
無名関数は変数または定数としての式です。
名前のない、無名関数を作成します。
const obj = function() { let myObj = { "name": "Taro", "age": 30, "city": "TOKYO" } return myObj; } console.log(obj()); /* { "name": "Taro", "age": 30, "city": "TOKYO" } */
結果は先程同様に出力されます。
唯一の違いは、関数から返すオブジェクトは変数内に格納されている事です。
アロー関数でオブジェクト返す場合も学びましょう。
アロー関数はオブジェクトのメソッドとしては思い通りにうまく機能してくれません、なので使用したくない場合もあったりします。
ですのでオブジェクト作成の場合は、波括弧{}とreturnを使用します。
下記では連想配列(オブジェクト)のドット表記の記法で作成します。
アロー関数ではコンストラクターとして使用はできません。
const obj = {}; const myObj = myData => { myData.name = "Taro"; myData.age = 30; myData.city = "TOKYO"; return myData } console.log(myObj(obj)); /* { "name": "Taro", "age": 30, "city": "TOKYO" } */
関数を呼び出す際に、始めに作成した空のオブジェクトを値として渡す事を忘れないように気をつけて下さい。
アロー関数では引数が1つの場合は括弧()が省略可能ですね。
そしてアロー関数での結果は『myObj』の変数に格納されています。
即時関数
即時関数とは手動で関数を呼びださなくても、定義されたときに自動的に実行される関数となります。
つまり自分自身を呼び出してる事になります。
この即時関数も他の関数とは異なります。
即時関数を作成するための構文には2つの種類があります。
(function () { // 内部 何かしらの処理 }());
2つめの代替えとなる即時関数
(function () { // 内部 何かしらの処理 })(); (() => { // 内部 何かしらの処理 })();
2番目の構文は、最初の構文よりも一般的です。
もう1つの違いそれは、ここまでしっかりと学んできてる方であれば、2つめの構文はすぐに理解ができたかと思います。
アロー関数を使用できる事です。
(function thisIsANamedIIFE() { alert("名前付き即時関数"); })(); let foo = function myself(greetings){ alert('Hello!!!'); //呼ばれる if(greetings === true) myself(false); }; foo(true); //呼ばれる //Hello!!! //Hello!!!
ですが最初の構文でアロー関数を使用を試みるとエラーがスローされます。
2つめの構文を紹介致します。
() () ↓ (function () {}) () ↓ (function () { alert("関数が自動で呼ばれました") }) ()
書き方は、先に括弧()を2つ入力してから括弧の間に関数のfunctionキーワードや波括弧などを記述していきます。
2つめの括弧は関数の実行として機能致します。
let x = (function (a,b){ let result = a + b; return result; })(1,2); alert(x); // 3
式としての即時関数の場合は関数に直に引数を渡しています、それを実行しています。
上記では無名関数の即時関数となります、名前がない即時関数です。
変数としての式で即時関数を定義した場合は、『x』の値が変更された場合、バグなどを追跡するのは非常に困難となります。
無名関数の場合、関数が割り当てられている変数の知識が必要にもなり、非常に難しい場合があります。
あまり理想的ではありません。
その場合は名前付き即時関数にしてあげます。
let foo = (function myself(greetings){ alert('Hello!!!'); //呼ばれる if(greetings === true) myself(false); })();
アロー関数表記で即時関数を使用する場合
アロー関数では名前付き関数は定義できませんので無名関数となる
(() => { alert('アロー関数の即時関数です');// 実行される })(); ((foo, num) => { let x = foo + num alert(x); })(1, 1); // 2
関数配列
矢印関数が使用される最も一般的な場所の1つは、map、reduce、filterなどのJavaScript配列メソッドです。
これらの配列メソッドでアロー関数を使用すると、1行で完全な配列変換を行うことができます。
const myArray = [1, 2, 3, 4].map(num => num * 2); console.log(myArray) /* [ 2, 4, 6, 8 ] */
上記では引数は1つなので括弧は省略させて頂いてます。
Array.map()メソッドを使用し数値を乗算(掛け算)した結果を『暗黙のリターン』で返してます。
アロー関数について覚えておくべき最も重要なことは、thisキーワードによる処理方法となりますが。
まずはJavaScriptのthisについて解説しないといけないのですがthisの理解は中級者レベルです。
thisでのアロー関数も通常の関数とはまったく異なります。
アロー関数でのthisの挙動はまた記事に致します。
その際は是非お立ち寄り下さい。
最後に
関数がどのように作成されても、関数は値です。
JavaScriptでは値として扱います、そしてコードの任意の場所で割り当て、コピーまたは宣言できます。
関数式では、実行フローが関数式に到達したときに作成され実行されます。
関数宣言では、コードブロックが実行される前に処理され、それらはブロック内のどこにでも表示されます。
アロー関数は、配列操作関数およびコールバック関数に最も最適となっております。
関数が式として扱われた場合それは、全て関数式(無名関数)となります。
本日は以上となります。
最後まで読んで頂きありがとうございます。
JavaScript 入門 関連記事
最新のJavaScriptでの文字列 — テキストの操作 - deve.K