関数
関数とは、複数の処理をひとまとめにしたものです。
JavaScriptの基本的な構文の一つでもあります。
関数には定義と呼び出しがあります。
- 定義: その関数でしたい処理を書く
- 呼び出し: 定義した処理を実行する
- JavaScriptでは関数名の後に
()
をつけると呼び出せる
- JavaScriptでは関数名の後に
関数の定義
関数は2通りの方法で定義することができます。
-
function
キーワードを使った関数宣言 - アロー関数式(
() =>
を使った記法)
ここからは、与えられた数値x, y
を足して返すadd
関数を例に説明します。
関数宣言
function
キーワードを使った関数宣言では、add
関数を以下のように書くことができます。
// function 関数名(引数) { 処理 }
function add(x, y) {
return x + y // returnで戻り値を決める
}
これは以下のように呼び出せます。
add(1, 2) // 3が返ってくる
アロー関数式
アロー関数式(() =>
を使った記法)では、add
関数を以下のように書くことができます。
// 変数の宣言 = 関数
// 関数の部分: (引数) => { 処理 }
const add = (x, y) => {
return x + y
}
アロー関数を使うと、関数という種類の値を作成できます。
これは普通の値なのでconst
などで宣言した通常の変数に代入できます。
これは、JavaScriptの関数が第一級の値だからできることです。
第一級の値とはざっくり言うと通常の値のことで、例えば数値や文字列があります。
関数が代入された変数は、通常通り呼び出すことができます。
add(3, 5) // 8
なお、アロー関数ではブロック({}
)を省略し、いきなり戻り値を書くこともできます。
const add = (x, y) => x + y
add(1, 3) // 4
関数式
なお、関数式と呼ばれる、function
キーワードと変数の代入を組み合わせる方法もあります
関数式はアロー関数と同じように変数に代入したりできます。
const add = function(x, y) {
return x + y
}
個人的にはこのように関数式を使う機会は少なく、これが必要な場面ではアロー関数に置き換えられると思っています。
実は、関数式では関数に名前をつけることができます。
// nameという名前をつける
const add = function name(x, y) {
return x + y
}
add(5, 3) // OK
name(2, 3) // NG、関数につけた名前では呼び出せない
ややこしいですが、これは関数宣言とは別物です。
// 関数式を変数に代入
const add = function name(x, y) {
return x + y
}
// 関数宣言
function add(x, y) {
return x + y
}
ちなみに、式文と呼ばれる、文を書く場所にいきなり式を書く場合があります。
これは例えば1;
みたいな文や、関数の呼び出し(add();
など)です。
ほとんどの式は式文として書くことができますが、関数式は式文にできません。
これは関数宣言との混同を避けるためです。
// 関数式を直接書くのは構文エラー
function() {
console.log('これはNG'); // <- ちなみにこれも関数の呼び出しなので式文
}
// 関数宣言ならOK
function test() {
console.log('これはOK');
}
// 関数式をconstなどの文で使う(=式文じゃない)のはOK
const test = function() {
console.log('これはNG');
};
リンク:
@juner ありがとうございました!
何が違うの?
では、アロー関数で定義した関数と、function
で定義した関数は、いったい何が違いのでしょうか。
結論から言うと、だいたい同じです。
そのため基本的には好みで使い分けてもいいと思います。
読みやすさ
これはあくまで個人の意見ですが、それぞれの記法にはこんな印象があります。
-
function
キーワード: なんだか関数感が出る - アロー関数: 関数を関数に渡す場合主流
高階関数とは
関数に関数を渡すとは、高階関数の呼び出しのことです。
高階関数とは引数に関数を取る関数(メソッド)のことで、配列のmap
やfilter
があります。
例えば、数値を入れた配列numbers
があるとします。
この中の値を2乗した配列を新しく作成したいです。
そんなときには、map
メソッドが使えます。
アロー関数の場合
下のコードではmap
にアロー関数を渡しています。
const numbers = [1, 4, 5]
const square = numbers.map(num => num ** 2)
// square: [1, 16, 25]
関数式の場合
以下のように関数式を使うこともできます。
const numbers = [1, 4, 5]
const square = numbers.map(function(num) { return num ** 2 })
// square: [1, 16, 25]
ですが、1行で済む関数に対していちいちブロック({}
)やreturn
を書く必要があるため、少し冗長になります。あと見慣れない
関数宣言の場合
function
キーワードを使って関数宣言し、それを使うこともできます。
const numbers = [1, 4, 5]
function toSquare(num) {
return num ** 2
}
const square = numbers.map(toSquare)
// square: [1, 16, 25]
しかしその関数を一度しか使わないことが自明な場合、無駄に複数行必要になったり無駄に名前をつけることになり、少し冗長です。
何度も使いそうな場合は、こちらのほうが再利用性が高くていいかもしれません。
this
アロー関数とfunction
を使った関数では、this
の扱いが違います。
this
は特別な変数で、どこで参照されるかによって値が違います。
例えば、ブラウザのグローバルから参照するとwindow
と同じオブジェクトが返ってきます。
オブジェクトの中で定義された関数のthis
はそのオブジェクト自身を指します。
const counter = {
count: 0,
add: function () {
this.count++ // thisはcounterを指す
return this.count
}
}
このコードのthis.count
はcounter
オブジェクトのcount
プロパティを指します。
そのため、add
を呼び出すとcounter.count
がインクリメントされます。
counter.add() // 1
counter.add() // 2
counter.add() // 3
ところが、このfunction
をアロー関数に変えた途端、事件は起きてしまいます。
なんと、counter.add
がNaN
を返すようになってしまいました。
const counter = {
count: 0,
add: () => {
this.count++
return this.count
}
}
counter.add() // NaN
counter.add() // NaN
これはなぜでしょうか。
実は、アロー関数の中のthis
は呼び出し元に影響を受けません。
アロー関数が定義された時点のthis
に固定されます。
function
を使った関数は、今回の呼び出し元=counter
オブジェクトに影響を受けます。
しかしアロー関数でのthis
は、宣言した場所でのthis
=window
が使われてしまいます。
これによって、初期化されていないwindow.count
が参照され、undefined
をインクリメントしたためwindow.count
がNaN
になってしまったようです。
個人的にはこの記法がすっきりしていてお気に入りです。
const counter = {
count: 0,
add() { // メソッド名(引数) {処理}
this.count++
return this.count
}
}
この記法は他より短く書けてすっきりします。
また、これはfunction
で宣言するときと同じように動作するので、this
はcounter
オブジェクトを指し、カウンターは正常に動きます。
参考リンク
function
を使った関数の詳細はこちらです。