もともとswiftで「クロージャ」について調べていました。するとJavaScriptでも同じ概念があるということで、記事数も多いJavaScriptで調べてみました。
特に感じたのが、クラスと似ているということ。そこでクラスとの違いの観点からクロージャの使い方についてまとめてみました。
イメージ
クロージャはクラスと同じようなことができ、比べるとこんなイメージです。
- クラスは「クラスの中に関数がある」
- クロージャは「関数の中に関数がある」
クラスの使い方
以前はJavaScriptにクラスという概念がなく、ES6で新しくクラスを作れるようになりました。
以下の例は、Userクラスを定義して名前を変更、取得する動きをします。
class User {
constructor() {
this._name = '太郎';
}
userName() {
return this._name;
}
setName(name) {
this._name = name;
}
}
const user = new User();
console.log(user.userName()); //太郎
user.setName('次郎');
console.log(user.userName()); //次郎
console.log(user.name); //undefined
get
やset
を関数の前につけるとゲッターとセッターにすることも機能としてありますが、今回はJavaのように書ける方を優先しているため使用していません。
プロパティはconstructor()
内で定義するのがちょっと面倒でしょうか。
また_name
など変数にアンダーバーを付けている理由は、プライベートな変数を表現するためです。ただし本当にプライベート変数になっているわけではなくconsole.log(user1._name)
で取得できてしまいます。あくまでルールとしてこのようにすることもできます。個人的な話ですが、実はアンダーバーをつければ勝手にプライベート変数になると勘違いしていたんですよね。。。
#クロージャの使い方
下の例は上のクラスの例と同じ動きです。
function funcUser() {
let name = '太郎';
return {
getName: function() {
return name;
},
setName: function(value) {
name = value;
}
};
}
const user = new funcUser();
console.log(user.getName()); //太郎
user.setName('次郎');
console.log(user.getName()); //次郎
console.log(user.name); //undefined
クロージャのイメージは関数の中に関数があるです。この形を取ることで外側の関数=クラスみたいな使い方ができます。
文法の説明ですが、関数の内部でも関数を書くことができるだけでなく、return
で関数を返すこともできます。さらにその返す関数をオブジェクト形式で関数を書くことで、呼び出し方が変数.関数名
の形で実行することができます。newするところもクラスの書き方と同じですね。
しかも関数内の変数にはアクセスできないので(関数スコープ)、実質プライベートなプロパティを作ることもできます。
#比較して
こうしてみるとクロージャの方が便利なのでは?と思いましたが、以下のようなデメリットもあります。
- 継承できない(クラスはできる)
- メモリリーク問題
- 他言語からきた人にとってとっつきにくい
なので基本的にはクラスを使った方が良く、クロージャは特殊な書き方の例として留めておくのが私の中での結論です。