LoginSignup
2
2

More than 3 years have passed since last update.

【JavaScript修行】アクセサーメソッドをしる(クロージャとdefineProperty)

Last updated at Posted at 2019-07-18

クロージャは、独立した (自由な) 変数を参照する関数です。言い換えるとクロージャ内で定義された関数は、自身が作成された環境を '覚えています'。

参考:MDN

なんだか意味深ですね。
わからなくて意味の深そうなものは全部意味深って言ってます。

早速だからクロージャをみてみます。

クロージャ
function closure () {
    var value = 0;

    return function next(){
        value++;
        console.log(value);
    };
};

let n = closure();
n();   //1
n();   //2
n();   //3

戻り値がfunctionになってます!
そのnext()の中でvalueを参照していますね。
nにはnext()が入っているので、呼び出すたびにvalueがプラス1されます。

それでクロージャってなんに使うの?

先ほどの例では、ファンクションであるにも関わらず、前回のvalueの値を元に
どんどん加算することができています。
まるでオブジェクトみたいな使用ができるんですね。

そしてクロージャ役に立つ方法を知る為に、、まずプライベートメンバについてまとめます。

プライベートメンバーって?

プライベートメンバー
・・・クラス内部からのみ呼び出せるプロパティ/メソッドのこと。
パブリックメンバー
・・・クラス内外から自由にアクセスできるメンバーのこと。

javascriptでは普通に定義するとパブリックメンバーになる。
→先ほどのクロージャを使うことで擬似的にプライベートメンバーを定義できる!

var プロパティ名
var メソッド名 = function(引数,...){}

これをコンストラクター関数の中で定義することで、プライベートメンバーにできます!
this.ほにゃらら= って書かないんですね。

プライベートメンバーにアクセスする方法

特権メソッド(プリビレッジメソッド)・・・プライベートメンバーにアクセスできるメソッド。
こいつらはコンストラクタ内で関数として定義する。⇨クロージャ!

クロージャでプライベートメンバーを使う
function Neko(){

    var _voice = "mew";          //プライベートプロパティ
    var _intro = function(){     //プライベートメソッド
        console.log("猫です");
    };

    this.getVoice = function(){    //特権メソッド
        return _voice
    };
    this.getIntro = function(){
        _intro();
    }
}

var neko = new Neko();
console.log(neko.getVoice());    //mew
neko.getIntro();     //猫です

もう1つ、プロパティ自体にアクセスさせない定義方法をみてみます。

アクセサーメソッド
function Neko(){

    var _voice;    //プライベートプロパティsetVo

    this.setVoice = function(voice){
        _voice = voice;
    }

    this.getVoice = function(){
        console.log(`${_voice}と鳴いた`);
    }
}

var neko = new Neko();
neko.setVoice('ミャー');
neko.getVoice();

プロパティを直接外部から操作せず、プロパティにアクセスする為のメソッドを準備しています。
こんなメソッドをアクセサーメソッドと言います。
また参照用メソッド(ここでいうgetVoice)をゲッターメソッド,
設定用メソッド(ここでいうsetVoice)をセッターメソッドと細かく呼ぶこともあります。

アクセサーメソッド

アクセサーメソッドなんて面倒くさいことしやがって!と思いましたが、
たくさんのメリットがあるようです。

①プロパティを書き込み専用にできる!
→ゲッターメソッドだけを用意すればいい!

②プロパティを読み取り専用にできる!
→セッターメソッドだけを用意すればいい!

③値の参照時にデータを加工できる!
→ミャーと鳴いた、というのがそうですね。他にも余計なデータをとったり付け足してわかりやすくしたり、、

④値の設定時に妥当性のチェックができる!
→おかしなデータを代入前に弾くことができますね。

でももっと簡単にアクセサーメソッドを実装する方法があるみたいです。
今までの方法はレガシー向けで使用していいみたいです。

definePropertyメソッド

Object.defineProperty(obj,prop,desc)
   //obj:プロパティの定義先のオブジェクト
   //prop:プロパティの名前
   //desc:プロパティの構成情報

descに対してget/setパラメータを指定すると、ゲッター/セッターを定義できます。

get/setパラメータ
function Neko(){
    var _voice;

    Object.defineProperty(
        this,'voice',
        {
            get:function(){
                return console.log(`${_voice}と鳴いた`);
            },
            set:function(voice){
                _voice = voice;
            }
        }
    )
}
var neko = new Neko();
neko.voice = 'にゃー';
neko.voice;   //にゃーと鳴いた

なきました!

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2