概要
JavaScript の値はすべて、論理型・数値型・文字列型など何らかの型を持ちます1。
もちろん関数も型を持ち、JavaScript の関数はオブジェクト型とされています。
関数がオブジェクト型であるということは、関数がプロパティをもつことができるということです。今回の記事は JavaScript の関数に独自プロパティを定義する方法について解説させていただきます。
この記事を読んでわかること
- JavaScript の関数に独自プロパティを定義する方法
- 関数に独自プロパティを定義することでできること
対象読者
- JavaScript 初心者
- JavaScript にある程度馴染みのある開発者
前提知識・環境
- JavaScript の文法の基本的な知識
JavaScript の関数に独自プロパティを定義する方法
JavaScript のオブジェクトのプロパティ
本題に入る前に、JavaScript のオブジェクトのプロパティについて簡単に確認しておきます。
const person = {
name: 'Mike',
age: 30,
hobbies: ['movie', 'baseball', 'reading']
};
console.log(person.name); // Mike
console.log(person['age']); // 30
オブジェクトのプロパティというと最初に思いつくのはこのようなケースですね。
person
オブジェクトは name
, age
, hobbies
など様々な型のプロパティを持ち、person.name
または person['age']
のような記述方法によってその値を取得することができます。
また、下記のようにあとからプロパティを追加することも可能です。
person.occupation = 'engineer';
person['nationality'] = 'japan';
console.log(person.occupation); // engineer
console.log(person.nationality); // japan
では関数のプロパティはどのように表現されるのでしょうか?
JavaScript の関数のプロパティ
関数も先程の例と同様に関数名に .
をつけてプロパティの値を取得できます。
const uniqueInteger = () => uniqueInteger.counter++;
uniqueInteger.counter = 0;
console.log(uniqueInteger.counter); // 0
console.log(uniqueInteger()); // 0
console.log(uniqueInteger.counter); // 1
console.log(uniqueInteger()); // 1
console.log(uniqueInteger.counter); // 2
console.log(uniqueInteger()); // 2
uniqueInteger
関数に counter
プロパティを設けることで uniqueInteger.counter
で counter
プロパティの値を取得できます。
また、uniqueInteger
関数自体は counter
プロパティ自体をインクリメントして返すので実行するたびに counter
プロパティの値が更新されます。
関数のプロパティの使用例
機能として関数にプロパティをもたせることができるということがわかりました。
ではどのように利用できるのでしょうか?
例えば下記のような階乗の計算を行う factorial
関数について見てみましょう。
const factorial = (n) => {
if (Number.isInteger(n) && n > 0) {
if (!(n in factorial)) {
factorial[n] = n * factorial(n - 1);
}
return factorial[n];
} else {
return NaN;
}
};
factorial[1] = 1;
console.log(factorial(6)); // 720
console.log(factorial[5]); // 120
factorial
関数は引数に任意の整数を受け取り、$n$ の階乗を計算します。
$n$ 番目のプロパティが保存されていなかった場合は factorial[n]
に計算結果を保存します。
したがって、factorial(6)
を実行済みの状況であれば factorial[5]
(5の階乗の計算結果)や factorial[3]
(3の階乗の計算結果)はプロパティとして保存された値からすぐに呼び出す事ができます。
このように JavaScript の関数のプロパティの使用例として実行結果をキャッシュとして保存しておくことが挙げられます。
JavaScript の関数のプロパティに関する個人的意見
今回紹介した中で uniqueInteger
関数を使って実行回数のカウントを行いました。
uniqueInteger
関数でプロパティを使用するメリット・デメリットそれぞれ考えて行きたいと思います。
uniqueInteger.counter
で関数の実行回数を管理するメリット
uniqueInteger.counter
で実行回数を管理するメリットは、counter
が uniqueInteger
関数の実行回数である とはっきりわかることだと思います。
例えば下記のように uniqueInteger
関数のスコープ外で変数宣言を行う場合、counter
は何に対して回数を数えているのか示されていません。
let counter = 0;
const uniqueInteger = () => counter++;
console.log(uniqueInteger()); // 0
console.log(uniqueInteger()); // 1
uniqueInteger
関数の処理を確認することで、その実行回数を数えていることを察することができますが、誤って counter
変数の値を関係のない箇所で更新してしまうかもしれません。
uniqueInteger.counter
として管理することで、どの関数の実行回数であるかがわかりやすくなります。
uniqueInteger.counter
で関数の実行回数を管理するデメリット
サンプルコードで示したように uniqueInteger.counter
として関数の実行回数を管理する場合、プロパティの初期値を関数のスコープ外で定める必要があります。
const uniqueInteger = () => uniqueInteger.counter++;
uniqueInteger.counter = 0; // 初期値の宣言
もし、初期値の宣言を忘れたり、コードを管理する過程でこの部分に余計な変更が加えられると予期せぬバグの原因となりそうです。
メリット・デメリットの両方について考えたうえで、今回のケースではクロージャを使った記述方法が筆者の好みです。クロージャを使った方法についてはまた別の記事で解説させていただきます。
最後まで読んでくださりありがとうございました🙇♂️
JavaScript のプロパティと考えると最初に示したオブジェクトのプロパティと想像される方が多いと思います。
関数でもプロパティを使えることを知っておくだけでコードを読むときの手助けになるはずです。